diff options
Diffstat (limited to 'source/Checking.hs')
| -rw-r--r-- | source/Checking.hs | 4265 |
1 files changed, 0 insertions, 4265 deletions
diff --git a/source/Checking.hs b/source/Checking.hs deleted file mode 100644 index ed5731a..0000000 --- a/source/Checking.hs +++ /dev/null @@ -1,4265 +0,0 @@ -{-# LANGUAGE MultiWayIf #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE RecordWildCards #-} -{-# OPTIONS_GHC -Wno-name-shadowing #-} - - -module Checking where - - -import Base hiding (locally) -import Checking.Core qualified as Core -import Checking.Dependencies qualified as Dependencies -import Checking.Datatype qualified as Datatype -import Checking.Exact.Vocabulary qualified as ExactVocabulary -import Checking.Facts qualified as Facts -import Checking.Kernel.Derivation - ( importIx - , importedFactDerivation - ) -import Checking.Legacy -import Checking.Obligation -import Checking.Structure qualified as Structure -import Checking.Transition qualified as Transition -import Checking.Typed.Atomic qualified as TypedAtomic -import Checking.Typed.Inductive qualified as TypedInductive -import Checking.Typed.Reflexivity qualified as TypedReflexivity -import StructGraph -import Syntax.Internal -import Syntax.Lexicon -import Encoding -import Report.Location - -import Bound.Scope -import Bound.Var (Var(..), unvar) -import Control.Exception (Exception) -import Control.Monad.Reader -import Control.Monad.State -import Data.Bifunctor (first) -import Data.HashMap.Strict qualified as HM -import Data.HashSet qualified as HS -import Data.IORef (newIORef, modifyIORef', readIORef) -import Data.List qualified as List -import Data.List.NonEmpty qualified as NonEmpty -import Data.Map.Strict qualified as Map -import Data.Set qualified as Set -import Data.Text qualified as Text -import Data.Text.IO qualified as Text -import Data.Vector (Vector) -import Data.Vector qualified as Vector -import System.FilePath.Posix -import UnliftIO.Directory - -type Checking = CheckingM () -type CheckingM = StateT CheckingState IO - --- | Like 'Base.locally', but preserves declaration-local counters across --- nested proof blocks. -locally :: CheckingM a -> CheckingM a -locally ma = do - st <- get - a <- ma - st' <- get - put - st - { checkingHypothesisCounter = - checkingHypothesisCounter st' - , checkingNextObligationOrdinal = - checkingNextObligationOrdinal st' - , checkingResolvedObligationBatches = - checkingResolvedObligationBatches st' - } - pure a - -check :: WithDumpPremselTraining -> [Block] -> IO [Task] -check dumpPremselTraining blocks = - fmap preparedObligationTask - <$> checkPrepared - dumpPremselTraining - id - blocks - -checkPrepared - :: WithDumpPremselTraining - -> (Task -> Task) - -> [Block] - -> IO [PreparedObligation] -checkPrepared dumpPremselTraining prepareTask blocks = do - obligationsRef <- newIORef [] - void - (runStateT - (checkBlocks blocks) - (initialCheckingStateWithTaskPreparation - dumpPremselTraining - prepareTask - (\batch -> - for_ - (preparedBatchObligations batch) - (\obligation -> - when - (preparedObligationMethod obligation - == ProveWithVampire) - (modifyIORef' - obligationsRef - (obligation :)))))) - reverse <$> readIORef obligationsRef - -checkWith - :: WithDumpPremselTraining - -> [Block] - -> (PreparedObligationBatch -> IO ()) - -> IO () -checkWith dumpPremselTraining blocks emitBatch = - void - (runStateT - (checkBlocks blocks) - (initialCheckingState - dumpPremselTraining - emitBatch)) - -initialCheckingState - :: WithDumpPremselTraining - -> (PreparedObligationBatch -> IO ()) - -> CheckingState -initialCheckingState dumpPremselTraining = - initialCheckingStateWithTaskPreparation - dumpPremselTraining - id - -initialCheckingStateWithTaskPreparation - :: WithDumpPremselTraining - -> (Task -> Task) - -> (PreparedObligationBatch -> IO ()) - -> CheckingState -initialCheckingStateWithTaskPreparation - dumpPremselTraining - prepareTask - emitBatch = - initialCheckingStateWithBatchHandler - dumpPremselTraining - prepareTask - (ObserveObligationBatches emitBatch) - Nothing - Nothing - -initialLegacyCheckingStateWithTaskPreparation - :: WithDumpPremselTraining - -> (Task -> Task) - -> LegacyModuleStage - -> (PreparedObligationBatch -> IO ResolvedObligationBatch) - -> CheckingState -initialLegacyCheckingStateWithTaskPreparation - dumpPremselTraining - prepareTask - stage - resolveBatch = - checkingStateWithEnvironment - (legacyStageImportedCheckingEnvironment stage) - ( (initialCheckingStateWithBatchHandler - dumpPremselTraining - prepareTask - (ResolveObligationBatches resolveBatch) - (Just stage) - Nothing) - { checkingFacts = legacyStageFactRegistry stage - } - ) - -initialTransitionCheckingStateWithTaskPreparation - :: WithDumpPremselTraining - -> (Task -> Task) - -> Transition.TransitionModuleBuilder - -> (PreparedObligationBatch -> IO ResolvedObligationBatch) - -> CheckingState -initialTransitionCheckingStateWithTaskPreparation - dumpPremselTraining - prepareTask - builder - resolveBatch = - checkingStateWithEnvironment - (Transition.transitionBuilderImportedCheckingEnvironment - builder) - ( (initialCheckingStateWithBatchHandler - dumpPremselTraining - prepareTask - (ResolveObligationBatches resolveBatch) - (Just - (Transition.transitionBuilderLegacyStage - builder)) - (Just builder)) - { checkingFacts = - legacyStageFactRegistry - (Transition.transitionBuilderLegacyStage - builder) - } - ) - --- | Production V1 checking uses the complete contracted task and has no --- premise-selection or training mode. -initialTransitionCheckingState - :: Transition.TransitionModuleBuilder - -> (PreparedObligationBatch -> IO ResolvedObligationBatch) - -> CheckingState -initialTransitionCheckingState = - initialTransitionCheckingStateWithTaskPreparation - WithoutDumpPremselTraining - contractionTask - -initialCheckingStateWithBatchHandler - :: WithDumpPremselTraining - -> (Task -> Task) - -> ObligationBatchHandler - -> Maybe LegacyModuleStage - -> Maybe Transition.TransitionModuleBuilder - -> CheckingState -initialCheckingStateWithBatchHandler - dumpPremselTraining - prepareTask - batchHandler - legacyStage - transitionBuilder = - CheckingState - { checkingAssumptions = [] - , checkingDumpPremselTraining = dumpPremselTraining - , checkingGoals = [] - , checkingFacts = Facts.emptyFactRegistry - , checkingDirectness = Direct - , checkingAbbreviations = initAbbreviations - , checkingPredicateDefinitions = mempty - , checkingDependencies = - Dependencies.fromRootSymbols (Set.fromList builtinSymbols) - , checkingOwnedSymbols = builtinOwnedSymbols - , checkingOwnedSymbolMarkers = builtinOwnedSymbolMarkers - , checkingFrozenSymbols = mempty - , checkingStructs = initCheckingStructs - , checkingStructContext = mempty - , definedMarkers = HS.empty - , blockLabel = Marker "" - , stepLocation = Nowhere - , blockEndLocation = Nowhere - , localVars = mempty - , checkingHypothesisCounter = 0 - , checkingNextObligationOrdinal = - legacyObligationOrdinal 0 - , checkingPrepareTask = prepareTask - , checkingObligationBatchHandler = batchHandler - , checkingResolvedObligationBatches = [] - , checkingDeclarationFactProducers = [] - , checkingLegacyModuleStage = legacyStage - , checkingTransitionModuleBuilder = - transitionBuilder - } - -runCheckingBlocks :: [Block] -> CheckingState -> IO CheckingState -runCheckingBlocks blocks checkingState = - snd <$> runStateT (checkBlocks blocks) checkingState - -checkingStateEnvironment - :: CheckingState - -> LegacyCheckingEnvironment -checkingStateEnvironment state = - legacyCheckingEnvironment - (checkingAbbreviations state) - (checkingPredicateDefinitions state) - (checkingDependencies state) - (checkingOwnedSymbols state) - (checkingOwnedSymbolMarkers state) - (checkingFrozenSymbols state) - (checkingStructs state) - (definedMarkers state) - -checkingStateWithEnvironment - :: LegacyCheckingEnvironment - -> CheckingState - -> CheckingState -checkingStateWithEnvironment environment state = - state - { checkingAbbreviations = - legacyEnvironmentAbbreviations environment - , checkingPredicateDefinitions = - legacyEnvironmentPredicateDefinitions environment - , checkingDependencies = - legacyEnvironmentDependencies environment - , checkingOwnedSymbols = - legacyEnvironmentOwnedSymbols environment - , checkingOwnedSymbolMarkers = - legacyEnvironmentOwnedSymbolMarkers environment - , checkingFrozenSymbols = - legacyEnvironmentFrozenSymbols environment - , checkingStructs = - legacyEnvironmentStructs environment - , definedMarkers = - legacyEnvironmentDefinedMarkers environment - } - -data WithDumpPremselTraining = WithoutDumpPremselTraining | WithDumpPremselTraining - -data ObligationBatchHandler - = ObserveObligationBatches - (PreparedObligationBatch -> IO ()) - | ResolveObligationBatches - (PreparedObligationBatch -> IO ResolvedObligationBatch) - --- | The checking state manages contextual information while checking and --- emits generated proof tasks through a callback. --- INVARIANT: All formulas in the checking state that eventually --- get exported should have all their abbreviations resolved. -data CheckingState = CheckingState - { checkingDumpPremselTraining :: WithDumpPremselTraining - - , checkingAssumptions :: [CurrentHypothesis] - -- ^ Local assumptions. - -- - , checkingGoals :: [Formula] - -- ^ The current goals. INVARIANT: these should always be canonicalized and have all abbreviations resolved. - -- - , checkingFacts :: Facts.FactRegistry - -- ^ Canonical axioms and proven results with separate registration metadata. - -- - -- - , checkingDirectness :: Directness - -- ^ E can detect contradictory axioms and warns about them. - -- In an indirect proof (e.g. a proof by contradiction) we want - -- to ignore that warning. - -- - , checkingAbbreviations :: HashMap Symbol (Scope Int ExprOf Void) - -- ^ Abbreviations are definitions that automatically get expanded. - -- They are given by a closed rhs (hence the 'Void' indicating no free variables). - -- INVARIANT: The bound 'Int' values must be lower than the arity of the symbol. - -- - , checkingPredicateDefinitions :: HashMap Predicate [Scope Int ExprOf Void] - -- ^ Definitions of predicate that we can match against in assumptions. - -- Axioms and theorems that have the shape of a definition can be added as alternate definitions. - -- - , checkingDependencies :: Dependencies.DependencyRegistry - -- ^ Backward-only dependencies of every owned symbol. - -- - , checkingOwnedSymbols :: HashMap Symbol SymbolOwner - -- ^ Top-level symbols with an established introducing owner in this document. - -- - , checkingOwnedSymbolMarkers :: HashSet Marker - -- ^ Object-language markers claimed by top-level symbols. - -- INVARIANT: contains the marker of every key in 'checkingOwnedSymbols'. - -- - , checkingFrozenSymbols :: HashMap Symbol Marker - -- ^ Symbols mentioned in an inductive specification may not be defined later. - -- - , checkingStructs :: StructGraph - -- ^ Graph of structs defined so far. - -- - , checkingStructContext :: StructContext - -- ^ Structure labels and operations in scope for carrier and operation annotation. - -- - , localVars :: Set VarSymbol - -- ^ Keeps track of the variables that are locally constant. - -- - , definedMarkers :: HashSet Marker - -- ^ Markers for toplevel sections need to be unique. This keeps track of the - -- markers used thus far. - -- - , blockLabel :: Marker -- ^ Label/marker of the current block - , stepLocation :: Location -- ^ Location of the current proof step - , blockEndLocation :: Location -- ^ Ending of the current proof block, useful for error messages for implicit QEDs. - , checkingHypothesisCounter :: Int -- ^ Counter for labeling local hypotheses within a proof. - , checkingNextObligationOrdinal :: LegacyObligationOrdinal - , checkingPrepareTask :: Task -> Task - , checkingObligationBatchHandler :: ObligationBatchHandler - , checkingResolvedObligationBatches - :: [ResolvedObligationBatch] - , checkingDeclarationFactProducers - :: [LegacyFactProducer] - , checkingLegacyModuleStage - :: Maybe LegacyModuleStage - , checkingTransitionModuleBuilder - :: Maybe Transition.TransitionModuleBuilder - } - -data CurrentHypothesis = CurrentHypothesis - !Hypothesis - !Location - !Marker - -data StructContext = StructContext - { structContextLabels :: Set VarSymbol - , structContextOps :: HashMap StructSymbol VarSymbol - } - -data BlockContext = BlockContext - { blockContextLocation :: !Location - , blockContextMarker :: !Marker - } - deriving (Show, Eq) - -instance Semigroup StructContext where - StructContext labels ops <> StructContext labels' ops' = - StructContext (labels <> labels') (ops <> ops') - -instance Monoid StructContext where - mempty = StructContext mempty mempty - -initCheckingStructs :: StructGraph -initCheckingStructs = StructGraph.insert - _Onesorted - mempty -- no parents - (Set.singleton CarrierSymbol) -- used for casting X -> \carrier[X] - (Set.singleton CarrierSymbol) - mempty -- empty graph - -initAbbreviations :: HashMap Symbol (Scope Int ExprOf Void) -initAbbreviations = HM.fromList - [ (SymbolPredicate (PredicateRelation NotElementSymbol), toScope (isNotElementOf Nowhere (TermVar (B 0)) (TermVar (B 1)))) - , (SymbolPredicate (PredicateVerb (mkLexicalItemSgPl (unsafeReadPhraseSgPl "equal[s/] ?") "eq")), toScope (Equals Nowhere (TermVar (B 0))( TermVar (B 1)))) - , (SymbolPredicate (PredicateNoun (mkLexicalItemSgPl (unsafeReadPhraseSgPl "element[/s] of ?") "elem")), toScope (isElementOf (TermVar (B 0)) (TermVar (B 1)))) - ] - -builtinOwnerMarker :: Marker -builtinOwnerMarker = Marker "<builtin>" - -builtinOwner :: SymbolOwner -builtinOwner = - SymbolOwner - { symbolOwnerKind = OwnedByBuiltin - , symbolOwnerMarker = builtinOwnerMarker - } - -builtinOwnedSymbols :: HashMap Symbol SymbolOwner -builtinOwnedSymbols = - HM.fromList - [ (symbol, builtinOwner) - | symbol <- builtinSymbols - ] - -builtinOwnedSymbolMarkers :: HashSet Marker -builtinOwnedSymbolMarkers = - HS.fromList - [ marker - | symbol <- builtinSymbols - , Just marker <- [objectSymbolMarker symbol] - ] - -initialLegacyCheckingEnvironment - :: LegacyCheckingEnvironment -initialLegacyCheckingEnvironment = - legacyCheckingEnvironment - initAbbreviations - mempty - (Dependencies.fromRootSymbols - (Set.fromList builtinSymbols)) - builtinOwnedSymbols - builtinOwnedSymbolMarkers - mempty - initCheckingStructs - mempty - -builtinReservedMixfixMarkers :: Set Marker -builtinReservedMixfixMarkers = - Set.fromList - [ "cons" - , "cumul" - , "emptyset" - , "naturals" - , "pair" - , "pow" - , "union" - ] - -builtinSymbols :: [Symbol] -builtinSymbols = - List.nub - ( [ SymbolMixfix mixfix - | level <- toList (lexiconMixfixTable builtins) - , mixfix <- Map.elems level - , mixfixMarker mixfix `Set.member` builtinReservedMixfixMarkers - ] - <> [ SymbolPredicate (PredicateRelation relation) - | relation <- lexiconRelationSymbols builtins - ] - <> [ SymbolPredicate (PredicateAdj adj) - | adj <- lexiconAdjLs builtins <> lexiconAdjRs builtins - ] - <> [ SymbolPredicate (PredicateVerb verb) - | verb <- lexiconVerbs builtins - ] - <> [ SymbolPredicate (PredicateNoun noun) - | noun <- lexiconNouns builtins - ] - <> [ SymbolPredicate (PredicateNounStruct noun) - | noun <- lexiconStructNouns builtins - ] - <> [ SymbolPredicate (PredicateSymbol name) - | (PrefixPredicate name _arity, _marker) <- lexiconPrefixPredicates builtins - ] - <> [ SymbolFun fun - | fun <- lexiconFuns builtins - ] - ) - -data CheckingError - = DuplicateMarker Location Marker - | UnknownStructureParent StructPhrase Location Marker - | ByContradictionOnMultipleGoals Location Marker - | BySetInductionSyntacticMismatch Location Marker - | ByOrdInductionSyntacticMismatch Location Marker - | SetExtensionalityWithTake Location Marker - | ProofWithoutPrecedingTheorem Location Marker - | CouldNotEliminateHigherOrder FunctionSymbol Term Location Marker - | UnresolvedStructureOperation StructSymbol Location Marker - | AmbiguousInductionVar Location Marker - | MismatchedSetExt [Formula] Location Marker - | MismatchedAssume Formula Formula Location Marker - | CheckingError Text Location Marker - deriving (Show, Eq) - -instance Exception CheckingError - -checkingErrorContext :: CheckingError -> (Location, Marker) -checkingErrorContext = \case - DuplicateMarker location marker -> (location, marker) - UnknownStructureParent _parent location marker -> (location, marker) - ByContradictionOnMultipleGoals location marker -> (location, marker) - BySetInductionSyntacticMismatch location marker -> (location, marker) - ByOrdInductionSyntacticMismatch location marker -> (location, marker) - SetExtensionalityWithTake location marker -> (location, marker) - ProofWithoutPrecedingTheorem location marker -> (location, marker) - CouldNotEliminateHigherOrder _symbol _term location marker -> - (location, marker) - UnresolvedStructureOperation _symbol location marker -> (location, marker) - AmbiguousInductionVar location marker -> (location, marker) - MismatchedSetExt _formulas location marker -> (location, marker) - MismatchedAssume _assumption _goal location marker -> (location, marker) - CheckingError _message location marker -> (location, marker) - -renderCheckingError :: CheckingError -> Text -renderCheckingError failure = - locationToText location - <> " in " <> markerTextOf marker <> ": " <> reason failure - where - (location, marker) = checkingErrorContext failure - - reason = \case - DuplicateMarker{} -> - "marker is already registered" - UnknownStructureParent parent _location _marker -> - "unknown parent structure " <> Text.pack (show parent) - ByContradictionOnMultipleGoals{} -> - "proof by contradiction requires exactly one open goal" - BySetInductionSyntacticMismatch{} -> - "the goal does not have the required set-induction shape" - ByOrdInductionSyntacticMismatch{} -> - "the goal does not have the required ordinal-induction shape" - SetExtensionalityWithTake{} -> - "set extensionality cannot be used after a Take step" - ProofWithoutPrecedingTheorem{} -> - "proof has no preceding theorem" - CouldNotEliminateHigherOrder symbol _term _location _marker -> - "could not eliminate higher-order symbol " - <> Text.pack (show symbol) - UnresolvedStructureOperation symbol _location _marker -> - "unresolved structure operation " <> Text.pack (show symbol) - AmbiguousInductionVar{} -> - "the induction variable is ambiguous" - MismatchedSetExt{} -> - "set extensionality does not match the open goal" - MismatchedAssume{} -> - "assumption does not match the open goal" - CheckingError message _location _marker -> - message - -data LegacyDeclarationAdmissionError - = LegacyFactRegistryIsNotAnExtension !Text - | LegacyFactProducerCountMismatch !Int !Int - | LegacyFactPremiseHasNoAuthorization - !LegacyObligationOrdinal - !Marker - | LegacyPreparedPremiseSelectionMismatch - !LegacyObligationOrdinal - | LegacyStageAdmissionFailed !LegacyModuleStageError - | TransitionStageAdmissionFailed - !Transition.TransitionModuleError - deriving (Show, Eq) - -instance Exception LegacyDeclarationAdmissionError - -throwWithLocationAndMarker :: (Location -> Marker -> CheckingError) -> CheckingM a -throwWithLocationAndMarker err = do - m <- gets blockLabel - loc <- gets stepLocation - throwIO (err loc m) - -throwWithMarker :: (Marker -> CheckingError) -> CheckingM a -throwWithMarker err = do - m <- gets blockLabel - throwIO (err m) - -assume :: [Asm] -> Checking -assume asms = traverse_ go asms - where - go :: Asm -> Checking - go = \case - Asm phi -> do - ctx <- structContextFromAssertion phi - addStructContextAndRefreshGoals ctx - assumeFormula phi - AsmStruct x sp -> - instantiateStruct x sp - -assumeFormula :: Formula -> Checking -assumeFormula phi = do - phi' <- canonicalize phi - let phiContracted = contraction phi' - case phiContracted of - Top -> skip - _ -> do - marker <- nextHypothesisMarker - let hypo = Hypothesis marker phi' - location <- gets stepLocation - declarationMarker <- gets blockLabel - modify \st -> - st - { checkingAssumptions = - CurrentHypothesis - hypo - location - declarationMarker - : checkingAssumptions st - } - -instantiateStruct :: VarSymbol -> StructPhrase -> Checking -instantiateStruct x sp = do - ctx <- structContextFor x sp - addStructContextAndRefreshGoals ctx - assumeFormula (structPredicate x sp) - -structPredicate :: VarSymbol -> StructPhrase -> Formula -structPredicate x sp = - TermSymbol Nowhere (SymbolPredicate (PredicateNounStruct sp)) [TermVar x] - -structContextFromAssertion :: Formula -> CheckingM StructContext -structContextFromAssertion = \case - TermSymbol _ (SymbolPredicate (PredicateNounStruct sp)) [TermVar x] -> - structContextFor x sp - _ -> - pure mempty - -structContextFor :: VarSymbol -> StructPhrase -> CheckingM StructContext -structContextFor x sp = do - structGraph <- gets checkingStructs - case StructGraph.lookupSymbols sp structGraph of - Nothing -> - throwWithLocationAndMarker (UnknownStructureParent sp) - Just symbols -> - pure (structContextFromSymbols x symbols) - -structContextFromSymbols :: VarSymbol -> Set StructSymbol -> StructContext -structContextFromSymbols x symbols = - StructContext (Set.singleton x) (HM.fromList [(op, x) | op <- Set.toList symbols]) - -addStructContext :: StructContext -> Checking -addStructContext ctx = - modify \st -> st - { checkingStructContext = ctx <> checkingStructContext st - } - -addStructContextAndRefreshGoals :: StructContext -> Checking -addStructContextAndRefreshGoals ctx - | structContextIsEmpty ctx = skip - | otherwise = do - addStructContext ctx - goals <- gets checkingGoals - setGoals goals - -structContextIsEmpty :: StructContext -> Bool -structContextIsEmpty StructContext{..} = - Set.null structContextLabels && HM.null structContextOps - -registerAssumptionStructContexts :: [Asm] -> Checking -registerAssumptionStructContexts asms = do - ctx <- assumptionStructContext asms - addStructContext ctx - -assumptionStructContext :: [Asm] -> CheckingM StructContext -assumptionStructContext asms = do - contexts <- traverse asmStructContext asms - pure (foldl' (\older newer -> newer <> older) mempty contexts) - -asmStructContext :: Asm -> CheckingM StructContext -asmStructContext = \case - Asm phi -> - structContextFromAssertion phi - AsmStruct x sp -> - structContextFor x sp - - -setLocation :: Location -> Checking -setLocation loc = modify \st -> st{stepLocation = loc} - - --- | Replace all current goals with a new goal. Use with care! -setGoals :: [Formula] -> Checking -setGoals goals = do - goals <- traverse canonicalize goals - modify $ \st -> st{checkingGoals = goals} - -nextHypothesisMarker :: CheckingM Marker -nextHypothesisMarker = do - st <- get - let next = checkingHypothesisCounter st + 1 - let marker = Marker ("_local_" <> Text.pack (show next)) - put st{checkingHypothesisCounter = next} - pure marker - -registerLemmaLocalVars :: [Asm] -> Formula -> Checking -registerLemmaLocalVars asms goal = - addLocalVars (Set.unions (freeVars goal : (asmLocalVars <$> asms))) - -asmLocalVars :: Asm -> Set VarSymbol -asmLocalVars = \case - Asm phi -> - freeVars phi - AsmStruct x _ -> - Set.singleton x - -addLocalVars :: Set VarSymbol -> Checking -addLocalVars vars = - modify \st -> st{localVars = vars <> localVars st} - -checkFreshLocalVars :: Text -> [VarSymbol] -> Checking -checkFreshLocalVars context vars = do - let duplicates = duplicateVars vars - unless (Set.null duplicates) do - throwCheckingError (context <> " introduces the same variable more than once: " <> formatVars duplicates) - inScope <- gets localVars - let shadowed = Set.fromList vars `Set.intersection` inScope - unless (Set.null shadowed) do - throwCheckingError (context <> " tries to introduce variable(s) already in scope: " <> formatVars shadowed) - -checkBinderVarsFresh :: Text -> [VarSymbol] -> Checking -checkBinderVarsFresh context vars = do - let duplicates = duplicateVars vars - unless (Set.null duplicates) do - throwCheckingError (context <> " uses the same binder variable more than once: " <> formatVars duplicates) - inScope <- gets localVars - let shadowed = Set.fromList vars `Set.intersection` inScope - unless (Set.null shadowed) do - throwCheckingError (context <> " binder variable(s) shadow local variable(s): " <> formatVars shadowed) - -assertKnownFormulaVars :: Text -> Formula -> Checking -assertKnownFormulaVars context phi = do - known <- gets localVars - assertKnownFormulaVarsWith context known phi - -assertKnownFormulaVarsWith :: Text -> Set VarSymbol -> Formula -> Checking -assertKnownFormulaVarsWith context known phi = do - let unknown = freeVars phi `Set.difference` known - unless (Set.null unknown) do - throwCheckingError (context <> " mentions variable(s) that are not in scope: " <> formatVars unknown) - -assertKnownTermVars :: Text -> Term -> Checking -assertKnownTermVars = assertKnownFormulaVars - -assertKnownTermVarsWith :: Text -> Set VarSymbol -> Term -> Checking -assertKnownTermVarsWith = assertKnownFormulaVarsWith - -throwCheckingError :: Text -> CheckingM a -throwCheckingError msg = - throwWithLocationAndMarker (CheckingError msg) - -duplicateVars :: [VarSymbol] -> Set VarSymbol -duplicateVars = - snd . foldl' step (Set.empty, Set.empty) - where - step (seen, duplicates) x - | x `Set.member` seen = (seen, Set.insert x duplicates) - | otherwise = (Set.insert x seen, duplicates) - -formatVars :: Set VarSymbol -> Text -formatVars vars = - Text.intercalate ", " (formatVar <$> Set.toList vars) - -formatVar :: VarSymbol -> Text -formatVar = \case - NamedVar x -> x - FreshVar n -> "_" <> Text.pack (show n) - -formatSymbols :: Set Symbol -> Text -formatSymbols symbols = - Text.intercalate ", " (symbolText <$> Set.toList symbols) - -ownableSymbol :: Symbol -> Bool -ownableSymbol = - isJust . objectSymbolMarker - -markerTextOf :: Marker -> Text -markerTextOf (Marker text) = text - -symbolText :: Symbol -> Text -symbolText = \case - SymbolMixfix symbol -> - markerTextOf (mixfixMarker symbol) - SymbolFun symbol -> - markerTextOf (lexicalItemSgPlMarker symbol) - SymbolInteger n -> - Text.pack (show n) - SymbolPredicate predicate -> - predicateText predicate - -predicateText :: Predicate -> Text -predicateText = - markerTextOf . predicateObjectMarker - -symbolOwnerKindText :: SymbolOwnerKind -> Text -symbolOwnerKindText = \case - OwnedByBuiltin -> - "builtin" - OwnedBySignaturePredicate -> - "signature predicate" - OwnedBySignatureFormula -> - "signature formula" - OwnedByAbbreviation -> - "abbreviation" - OwnedByPredicateDefinition -> - "predicate definition" - OwnedByFunctionDefinition -> - "function definition" - OwnedByOperatorDefinition -> - "operator definition" - OwnedByDatatypeHead -> - "datatype" - OwnedByDatatypeConstructor -> - "datatype constructor" - OwnedByInductiveDefinition -> - "inductive definition" - OwnedByStructureDefinition -> - "structure definition" - -symbolOwnerText :: SymbolOwner -> Text -symbolOwnerText SymbolOwner{symbolOwnerKind, symbolOwnerMarker} = - symbolOwnerKindText symbolOwnerKind - <> " " - <> markerTextOf symbolOwnerMarker - --- Multiple matches can only be builtin aliases, which all have 'builtinOwner'. -symbolOwnerByMarker :: Marker -> HashMap Symbol SymbolOwner -> Maybe SymbolOwner -symbolOwnerByMarker marker owners = - snd <$> List.find ((== Just marker) . objectSymbolMarker . fst) (HM.toList owners) - -validatedOwnership - :: Marker - -> SymbolOwnerKind - -> Symbol - -> CheckingState - -> Either Text (HashMap Symbol SymbolOwner, HashSet Marker) -validatedOwnership currentMarker ownerKind symbol st = do - marker <- - maybe - (Left ("symbol has no object marker: " <> symbolText symbol)) - Right - (objectSymbolMarker symbol) - let owners = checkingOwnedSymbols st - for_ (HM.lookup symbol owners) \owner -> - Left - ( "symbol " - <> symbolText symbol - <> " is already owned by " - <> symbolOwnerText owner - ) - let ownedMarkers = checkingOwnedSymbolMarkers st - when (marker `HS.member` ownedMarkers) do - Left - ( "object-symbol marker " - <> markerTextOf marker - <> " is already owned" - <> maybe - "" - ((" by " <>) . symbolOwnerText) - (symbolOwnerByMarker marker owners) - ) - case HM.lookup symbol (checkingFrozenSymbols st) of - Just frozenBy | frozenBy /= currentMarker -> - Left - ( "symbol " - <> symbolText symbol - <> " is frozen by inductive block " - <> markerTextOf frozenBy - <> " and cannot be defined here" - ) - _ -> - Right - ( HM.insert - symbol - (SymbolOwner ownerKind currentMarker) - owners - , HS.insert marker ownedMarkers - ) - -dependencyRegistrationErrorText - :: Symbol - -> Dependencies.DependencyRegistrationError - -> Text -dependencyRegistrationErrorText owner = \case - Dependencies.DependencyOwnerAlreadyRegistered _ -> - "dependencies are already registered for symbol " <> symbolText owner - Dependencies.SelfDependency _ -> - "definition of symbol " <> symbolText owner <> " is self-referential" - Dependencies.UnknownDependency unknown -> - "definition of symbol " - <> symbolText owner - <> " depends on unknown symbol " - <> symbolText unknown - -validatedSymbolRegistration - :: BlockContext - -> SymbolOwnerKind - -> Symbol - -> Set Symbol - -> CheckingState - -> Either - CheckingError - ( HashMap Symbol SymbolOwner - , HashSet Marker - , Dependencies.DependencyRegistry - ) -validatedSymbolRegistration context ownerKind symbol dependencies st = - case objectSymbolMarker symbol of - Nothing -> - Right - ( checkingOwnedSymbols st - , checkingOwnedSymbolMarkers st - , checkingDependencies st - ) - Just _marker -> do - (owners', ownedMarkers') <- - first - (checkingErrorAt context) - (validatedOwnership - (blockContextMarker context) - ownerKind - symbol - st) - dependencies' <- - first - ( checkingErrorAt context - . dependencyRegistrationErrorText symbol - ) - (Dependencies.registerDependencies - symbol - (Set.filter ownableSymbol dependencies) - (checkingDependencies st)) - pure (owners', ownedMarkers', dependencies') - -validateOwnedDependenciesAt - :: BlockContext - -> HashMap Symbol SymbolOwner - -> Set Symbol - -> Either CheckingError () -validateOwnedDependenciesAt context owners dependencies = - unless (Set.null unknown) do - Left - (checkingErrorAt - context - ( "top-level fact mentions symbol(s) without prior ownership: " - <> formatSymbols unknown - )) - where - unknown = - Set.filter - (\symbol -> - ownableSymbol symbol - && not (HM.member symbol owners)) - dependencies - -validatePreparedSemanticFact - :: BlockContext - -> HashMap Symbol SymbolOwner - -> Dependencies.DependencyRegistry - -> Facts.PreparedSemanticFact - -> Either CheckingError () -validatePreparedSemanticFact context owners dependencies prepared = do - validateOwnedDependenciesAt context owners semanticDependencies - unless (Set.null unknownDependencies) do - Left - (checkingErrorAt - context - ( "top-level fact depends on unknown symbol(s): " - <> formatSymbols unknownDependencies - )) - where - semanticDependencies = - Facts.preparedSemanticDependencies prepared - unknownDependencies = - Set.filter - (\symbol -> - ownableSymbol symbol - && isNothing - (Dependencies.lookupDependencies - symbol - dependencies)) - semanticDependencies - -checkedInductiveMentionedSymbols :: CheckedInductive -> Set Symbol -checkedInductiveMentionedSymbols CheckedInductive{checkedInductiveSymbol, checkedInductiveDomain, checkedInductiveIntros} = - Set.insert - (SymbolMixfix checkedInductiveSymbol) - ( mentionedSymbols checkedInductiveDomain - <> Set.unions (checkedInductiveIntroMentionedSymbols <$> NonEmpty.toList checkedInductiveIntros) - ) - -checkedInductiveIntroMentionedSymbols :: CheckedInductiveIntro -> Set Symbol -checkedInductiveIntroMentionedSymbols CheckedInductiveIntro{checkedInductiveIntroConditions, checkedInductiveIntroResultTerm} = - mentionedSymbols checkedInductiveIntroResultTerm - <> Set.unions (checkedInductiveConditionMentionedSymbols <$> checkedInductiveIntroConditions) - -checkedInductiveConditionMentionedSymbols :: CheckedInductiveCondition -> Set Symbol -checkedInductiveConditionMentionedSymbols = \case - CheckedInductiveSideCondition phi -> - mentionedSymbols phi - CheckedInductiveRecursiveCondition{checkedInductiveRecursiveTerm, checkedInductiveRecursiveCarrierTemplate} -> - mentionedSymbols checkedInductiveRecursiveTerm - <> mentionedSymbols (fromScope checkedInductiveRecursiveCarrierTemplate) - -formatSymbolPath :: NonEmpty Symbol -> Text -formatSymbolPath = - Text.intercalate " -> " . fmap symbolText . toList - -definitionParts :: Defn -> (SymbolOwnerKind, Symbol, [Asm], Expr) -definitionParts = \case - DefnPredicate asms predicate _vs body -> - (OwnedByPredicateDefinition, SymbolPredicate predicate, asms, body) - DefnFun asms fun _vs rhs -> - (OwnedByFunctionDefinition, SymbolFun fun, asms, rhs) - DefnOp op _vs rhs -> - (OwnedByOperatorDefinition, SymbolMixfix op, [], rhs) - -checkedDefinitionDependencies :: Symbol -> [Asm] -> Expr -> CheckingM (Set Symbol) -checkedDefinitionDependencies symbol asms definiens = do - assumptionFormulas <- traverse asmFormula asms - expandedAssumptions <- traverse unabbreviate assumptionFormulas - expandedDefiniens <- unabbreviate definiens - let dependencies = - mentionedSymbols expandedDefiniens - <> Set.unions (mentionedSymbols <$> expandedAssumptions) - when (symbol `Set.member` dependencies) do - throwCheckingError - ("definition of symbol " <> symbolText symbol <> " is self-referential") - pure dependencies - -checkDatatype :: BlockContext -> Syntax.Internal.Datatype -> Checking -checkDatatype context datatype = do - structContext <- gets checkingStructContext - checked <- - Datatype.prepareCheckedDatatype - (canonicalizeWithAt context structContext) - datatype - >>= either - ( throwIO - . checkingErrorAt context - . Datatype.renderDatatypeValidationError - ) - pure - st <- get - committed <- - either - throwIO - pure - (commitCheckedDatatype context checked st) - putDeclarationCandidate committed - setDeclarationFactProducers - ( LegacyDeclarationRuleProducer - . LegacyDatatypeRule - <$> NonEmpty.toList - (Datatype.checkedDatatypeFactRoles checked) - ) - --- | Validate and commit every state row introduced by one datatype. -commitCheckedDatatype - :: BlockContext - -> Datatype.CheckedDatatype - -> CheckingState - -> Either CheckingError CheckingState -commitCheckedDatatype context checked st = do - blockMarkers <- - validatedMarkers - location - [blockMarker] - st - (owners', ownedMarkers') <- - foldM validateOwner - (checkingOwnedSymbols st, checkingOwnedSymbolMarkers st) - ownedSymbols - markers' <- - validatedMarkers - location - factMarkers - st{definedMarkers = blockMarkers} - dependencies' <- - foldM registerDependency - (checkingDependencies st) - (snd <$> ownedSymbols) - traverse_ - (validatePreparedDatatypeFact - context - owners' - dependencies') - (Facts.stagedFactSemantic <$> stagedFacts) - facts' <- - first - (DuplicateMarker location) - (Facts.registerStagedFacts - stagedFacts - (checkingFacts st)) - pure - st - { checkingFacts = facts' - , checkingDependencies = dependencies' - , checkingOwnedSymbols = owners' - , checkingOwnedSymbolMarkers = ownedMarkers' - , definedMarkers = markers' - , blockLabel = blockMarker - , stepLocation = location - , checkingHypothesisCounter = 0 - } - where - location = blockContextLocation context - blockMarker = blockContextMarker context - stagedFacts = - Datatype.checkedDatatypeFacts location blockMarker checked - factMarkers = - toList (stagedFacts >>= Facts.stagedFactAliases) - ownedSymbols = - ( OwnedByDatatypeHead - , Datatype.checkedDatatypeHeadSymbol checked - ) - : [ (OwnedByDatatypeConstructor, symbol) - | symbol <- - toList - (Datatype.checkedDatatypeConstructorSymbols checked) - ] - - validateOwner - (owners, ownedMarkers) - (ownerKind, symbol) = - first - (checkingErrorAt context) - (validatedOwnership - blockMarker - ownerKind - symbol - st - { checkingOwnedSymbols = owners - , checkingOwnedSymbolMarkers = ownedMarkers - }) - - registerDependency dependencies symbol = - first - ( checkingErrorAt context - . dependencyRegistrationErrorText symbol - ) - (Dependencies.registerDependencies - symbol - mempty - dependencies) - -validatePreparedDatatypeFact - :: BlockContext - -> HashMap Symbol SymbolOwner - -> Dependencies.DependencyRegistry - -> Facts.PreparedSemanticFact - -> Either CheckingError () -validatePreparedDatatypeFact context owners dependencies prepared = - case Set.lookupMin unknownOwners of - Just _unknown -> - Left - (checkingErrorAt - context - ( "top-level fact mentions symbol(s) without prior ownership: " - <> formatSymbols unknownOwners - )) - Nothing -> - case Set.lookupMin unknownDependencies of - Nothing -> - Right () - Just unknown -> - Left - (checkingErrorAt - context - ( "datatype fact depends on unknown symbol " - <> symbolText unknown - )) - where - semanticDependencies = - Facts.preparedSemanticDependencies prepared - unknownOwners = - Set.filter - (\symbol -> - requiresDatatypeOwnership symbol - && not (HM.member symbol owners)) - semanticDependencies - unknownDependencies = - Set.filter - (\symbol -> - requiresDatatypeOwnership symbol - && isNothing - (Dependencies.lookupDependencies - symbol - dependencies)) - semanticDependencies - - -- Exact fixed terms do not require a legacy source declaration. - requiresDatatypeOwnership symbol = - ownableSymbol symbol - && case ExactVocabulary.classifyExactSymbol symbol of - ExactVocabulary.ExactFixedPrimitive{} -> False - _ -> True - -functionSymbolText :: FunctionSymbol -> Text -functionSymbolText symbol = case mixfixMarker symbol of - Marker name -> name - -freshDatatypeVar :: Set VarSymbol -> Text -> VarSymbol -freshDatatypeVar used base = - List.head - [ NamedVar candidate - | candidate <- base : [base <> Text.pack (show n) | n <- [(1 :: Int)..]] - , NamedVar candidate `Set.notMember` used - ] - -freshGeneratedVar :: Set VarSymbol -> Text -> VarSymbol -freshGeneratedVar = freshDatatypeVar - -forallIfNeeded :: [VarSymbol] -> Formula -> Formula -forallIfNeeded [] phi = phi -forallIfNeeded xs phi = makeForall xs phi - -existsIfNeeded :: [VarSymbol] -> Formula -> Formula -existsIfNeeded [] phi = phi -existsIfNeeded xs phi = makeExists xs phi - -impliesFrom :: [Formula] -> Formula -> Formula -impliesFrom [] conclusion = conclusion -impliesFrom premises conclusion = makeConjunction premises `Implies` conclusion - - --- | Prepare one complete current goal batch. -tellTasks :: Checking -tellTasks = - emitCurrentObligations ProveWithVampire - -omitCurrentGoals :: Location -> Checking -omitCurrentGoals location = do - emitCurrentObligations (RecordExplicitGap location) - setGoals [] - -emitCurrentObligations :: ObligationMethod -> Checking -emitCurrentObligations method = do - goals <- gets checkingGoals - marker <- gets blockLabel - facts <- gets checkingFacts - assumptions <- gets checkingAssumptions - directness <- gets checkingDirectness - location <- gets stepLocation - firstOrdinal <- gets checkingNextObligationOrdinal - prepareTask <- gets checkingPrepareTask - batchHandler <- gets checkingObligationBatchHandler - legacyStage <- gets checkingLegacyModuleStage - let premises = - factPremises legacyStage facts - <> (currentHypothesisPremise <$> assumptions) - (batch, nextOrdinal) = - case method of - ProveWithVampire -> - prepareObligationBatch - prepareTask - firstOrdinal - premises - directness - marker - location - goals - RecordExplicitGap gapLocation -> - prepareOmittedObligationBatch - prepareTask - firstOrdinal - premises - directness - marker - gapLocation - goals - modify \st -> - st - { checkingNextObligationOrdinal = - nextOrdinal - } - case batchHandler of - ObserveObligationBatches emitBatch -> - liftIO (emitBatch batch) - ResolveObligationBatches resolveBatch -> do - resolved <- liftIO (resolveBatch batch) - modify \st -> - st - { checkingResolvedObligationBatches = - checkingResolvedObligationBatches st - <> [resolved] - } - -factPremises - :: Maybe LegacyModuleStage - -> Facts.FactRegistry - -> [PreparedPremise] -factPremises legacyStage facts = - [ preparedPremise - (Hypothesis marker (Facts.preparedSemanticStatement fact)) - (case legacyStage >>= lookupLegacyStageFact marker of - Nothing -> - RegisteredFactPremise origin - Just entry -> - RegisteredLegacyFactPremise - (legacyFactEntryReference entry) - origin - (legacyFactEntryTrustDependencies entry)) - | (marker, fact, origin) <- - Facts.registeredFactsWithOrigins facts - ] - -factHypotheses :: Facts.FactRegistry -> [Hypothesis] -factHypotheses = - fmap preparedPremiseHypothesis . factPremises Nothing - -currentHypothesisPremise :: CurrentHypothesis -> PreparedPremise -currentHypothesisPremise - (CurrentHypothesis hypothesis location marker) = - preparedPremise - hypothesis - (LocalHypothesisPremise location marker) - -stagePreparedFact - :: Location - -> Marker - -> Marker - -> Facts.PreparedSemanticFact - -> Facts.StagedFact -stagePreparedFact loc blockMarker factMarker = - Facts.stageFact - (factMarker :| []) - (Facts.factOrigin loc blockMarker) - -validatedMarkers - :: Location - -> [Marker] - -> CheckingState - -> Either CheckingError (HashSet Marker) -validatedMarkers loc markers st = - case firstDuplicateMarker (definedMarkers st) HS.empty markers of - Just marker -> - Left (DuplicateMarker loc marker) - Nothing -> - Right (foldr HS.insert (definedMarkers st) markers) - -firstDuplicateMarker - :: HashSet Marker - -> HashSet Marker - -> [Marker] - -> Maybe Marker -firstDuplicateMarker _seenGlobals _seenLocals [] = - Nothing -firstDuplicateMarker seenGlobals seenLocals (marker:rest) - | HS.member marker seenGlobals || HS.member marker seenLocals = - Just marker - | otherwise = - firstDuplicateMarker - seenGlobals - (HS.insert marker seenLocals) - rest - - - -canonicalizedFactWithAsms :: [Asm] -> Formula -> CheckingM Formula -canonicalizedFactWithAsms asms stmt = do - (asms', structContext) <- mergeAssumptions asms - asms'' <- traverse (canonicalizeWith structContext) asms' - stmt' <- canonicalizeWith structContext stmt - pure - (case asms'' of - [] -> forallClosure mempty stmt' - _ -> forallClosure mempty (makeConjunction asms'' `Implies` stmt') - ) - -unabbreviateWith :: (forall a. HashMap Symbol (Scope Int ExprOf a)) -> (forall b. ExprOf b -> ExprOf b) -unabbreviateWith abbrs = unabbr - where - unabbr :: ExprOf b -> ExprOf b - unabbr = \case - TermSymbol loc sym es -> - let es' = unabbr <$> es - in case HM.lookup sym abbrs of - Nothing -> TermSymbol loc sym es' - Just scope -> - unabbr - (instantiate - (\k -> - nth k es - ?? impossible - "abbreviation index exceeds application arity") - scope) - Not loc e -> - Not loc (unabbr e) - Apply e es -> - Apply (unabbr e) (unabbr <$> es) - TermSep vs e scope -> - TermSep vs (unabbr e) (hoistScope unabbr scope) - ReplacePred y x xB scope -> - ReplacePred y x (unabbr xB) (hoistScope unabbr scope) - ReplaceFun bounds scope cond -> - ReplaceFun ((\(x, e) -> (x, unabbr e)) <$> bounds) (hoistScope unabbr scope) (hoistScope unabbr cond) - Connected con e1 e2 -> - Connected con (unabbr e1) (unabbr e2) - Lambda scope -> - Lambda (hoistScope unabbr scope) - Quantified quant scope -> - Quantified quant (hoistScope unabbr scope) - e@PropositionalConstant{} -> - e - e@TermVar{} -> - e - TermSymbolStruct symb e -> - TermSymbolStruct symb (unabbr <$> e) - -mentionsSymbol :: Symbol -> ExprOf a -> Bool -mentionsSymbol target = \case - TermVar{} -> - False - TermSymbol _loc sym es -> - sym == target || any (mentionsSymbol target) es - TermSymbolStruct _symb e -> - maybe False (mentionsSymbol target) e - Apply e es -> - mentionsSymbol target e || any (mentionsSymbol target) es - TermSep _x bound scope -> - mentionsSymbol target bound || mentionsSymbol target (fromScope scope) - ReplacePred _y _x bound scope -> - mentionsSymbol target bound || mentionsSymbol target (fromScope scope) - ReplaceFun bounds lhs cond -> - any (mentionsSymbol target . snd) bounds - || mentionsSymbol target (fromScope lhs) - || mentionsSymbol target (fromScope cond) - Connected _conn e1 e2 -> - mentionsSymbol target e1 || mentionsSymbol target e2 - Lambda scope -> - mentionsSymbol target (fromScope scope) - Quantified _quant scope -> - mentionsSymbol target (fromScope scope) - PropositionalConstant{} -> - False - Not _loc e -> - mentionsSymbol target e - --- | Unroll supported comprehensions in equations and reject leftover ones. --- E.g. /@B = \\{f(a) | a\\in A \\}@/ turns into --- /@\\forall b. b\\in B \\iff \\exists a\\in A. b = f(a)@/. -desugarComprehensionsAt - :: BlockContext - -> ExprOf a - -> CheckingM (ExprOf a) -desugarComprehensionsAt context = go - where - go :: forall b. ExprOf b -> CheckingM (ExprOf b) - go = \case - -- We only desugar comprehensions directly under equations. - -- Any remaining comprehension is currently unsupported. - e@TermSep{} -> - reject e - e@ReplacePred{} -> - reject e - e@ReplaceFun{} -> - reject e - e@TermVar{} -> - pure e - e@PropositionalConstant{} -> - pure e - TermSymbolStruct symbol Nothing -> - throwIO - (UnresolvedStructureOperation - symbol - (blockContextLocation context) - (blockContextMarker context)) - TermSymbolStruct symbol (Just argument) -> - TermSymbolStruct symbol . Just <$> go argument - -- - Equals _pos e (TermSep x bound scope) -> - go (desugarSeparation e x bound scope) - Equals _pos (TermSep x bound scope) e -> - go (desugarSeparation e x bound scope) - -- - Equals _pos e (ReplaceFun bounds scope cond) -> - go (makeReplacementIff (F <$> e) bounds scope cond) - Equals _pos (ReplaceFun bounds scope cond) e -> - go (makeReplacementIff (F <$> e) bounds scope cond) - -- - Apply e es -> - Apply <$> go e <*> traverse go es - Not loc e -> - Not loc <$> go e - TermSymbol loc sym es -> - TermSymbol loc sym <$> traverse go es - Connected conn e1 e2 -> - Connected conn <$> go e1 <*> go e2 - Lambda scope -> - Lambda <$> transverseScope go scope - Quantified quant scope -> - Quantified quant <$> transverseScope go scope - - reject :: ExprOf a -> CheckingM b - reject _ = - throwIO - (CheckingError - "Could not eliminate set comprehensions in this step. Nested comprehensions are not supported yet." - (blockContextLocation context) - (blockContextMarker context)) - - desugarSeparation - :: ExprOf a - -> VarSymbol - -> ExprOf a - -> Scope () ExprOf a - -> ExprOf a - desugarSeparation e x bound scope = - let phi = isElementOf (TermVar (B x)) (F <$> e) - psi = isElementOf (TermVar (B x)) (F <$> bound) - rho = fromScope (mapBound (const x) scope) - in Quantified Universally (toScope (phi `Iff` (psi `And` rho))) - - - - -checkBlocks :: [Block] -> Checking -checkBlocks = \case - BlockAxiom loc marker axiom : blocks -> do - let context = BlockContext loc marker - withBlockContext context (checkAxiom context axiom) - checkBlocks blocks - BlockDefn loc marker defn : blocks -> do - let context = BlockContext loc marker - withBlockContext context (checkDefn context defn) - checkBlocks blocks - BlockAbbr loc marker abbr : blocks -> do - let context = BlockContext loc marker - withBlockContext context (checkAbbr context abbr) - checkBlocks blocks - BlockLemma loc marker lemma : BlockProof _startLoc endLoc proof : blocks -> do - modify \st -> st{blockEndLocation = endLoc} - let context = BlockContext loc marker - withBlockContext - context - (checkLemmaWithProof context lemma proof) - checkBlocks blocks - BlockLemma loc marker lemma : blocks -> do - let context = BlockContext loc marker - withBlockContext context (checkLemma context lemma) - checkBlocks blocks - BlockProof startLoc _endLoc _proof : _ -> - throwWithMarker (ProofWithoutPrecedingTheorem startLoc) - BlockSig loc marker asms sig : blocks -> do - let context = BlockContext loc marker - withBlockContext context (checkSig context asms sig) - checkBlocks blocks - BlockData loc marker datatype : blocks -> do - let context = BlockContext loc marker - withBlockContext context (checkDatatype context datatype) - checkBlocks blocks - BlockInductive loc marker inductiveDefn : blocks -> do - let context = BlockContext loc marker - withBlockContext - context - (checkInductive context inductiveDefn) - checkBlocks blocks - BlockStruct loc marker structDefn : blocks -> do - let context = BlockContext loc marker - withBlockContext context (checkStructDefn context structDefn) - checkBlocks blocks - [] -> skip - --- | Make a block's diagnostic context current without publishing its label. -withBlockContext :: BlockContext -> CheckingM a -> CheckingM a -withBlockContext BlockContext{blockContextLocation, blockContextMarker} ma = do - previous <- get - modify \st -> - st - { blockLabel = blockContextMarker - , stepLocation = blockContextLocation - , checkingHypothesisCounter = 0 - , checkingNextObligationOrdinal = - legacyObligationOrdinal 0 - , checkingResolvedObligationBatches = [] - , checkingDeclarationFactProducers = [] - , checkingTransitionModuleBuilder = - Transition.beginTransitionDeclaration - <$> checkingTransitionModuleBuilder st - } - result <- ma - finalizeLegacyDeclaration previous - pure result - -setDeclarationFactProducers - :: [LegacyFactProducer] - -> Checking -setDeclarationFactProducers producers = - modify \st -> - st{checkingDeclarationFactProducers = producers} - -putDeclarationCandidate :: CheckingState -> Checking -putDeclarationCandidate candidate = do - current <- get - put - candidate - { checkingHypothesisCounter = - checkingHypothesisCounter current - , checkingNextObligationOrdinal = - checkingNextObligationOrdinal current - , checkingResolvedObligationBatches = - checkingResolvedObligationBatches current - , checkingDeclarationFactProducers = - checkingDeclarationFactProducers current - } - -finalizeLegacyDeclaration :: CheckingState -> Checking -finalizeLegacyDeclaration previous = do - current <- get - case checkingLegacyModuleStage current of - Nothing -> - pure () - Just stage -> do - stagedFacts <- - either - (throwIO - . LegacyFactRegistryIsNotAnExtension) - pure - (Facts.factRegistryExtension - (checkingFacts previous) - (checkingFacts current)) - let producers = - checkingDeclarationFactProducers current - unless - (length producers == length stagedFacts) - (throwIO - (LegacyFactProducerCountMismatch - (length producers) - (length stagedFacts))) - case stagedFacts of - [] -> - pure () - firstStaged : remainingStaged -> do - reservation <- - either - (throwIO - . LegacyStageAdmissionFailed) - pure - (reserveLegacyDeclaration - (firstStaged :| remainingStaged) - stage) - admitted <- - authorizeLegacyDeclaration - stage - reservation - producers - (checkingResolvedObligationBatches - current) - stage' <- - either - (throwIO - . LegacyStageAdmissionFailed) - pure - (appendEstablishedLegacyDeclaration - reservation - admitted - stage) - unless - (legacyStageFactRegistry stage' - == checkingFacts current) - (throwIO - (LegacyFactRegistryIsNotAnExtension - "checker and legacy-stage fact registries diverged")) - transitionBuilder' <- - traverse - (either - (throwIO - . TransitionStageAdmissionFailed) - pure - . Transition.transitionBuilderWithLegacyStage - stage') - (checkingTransitionModuleBuilder - current) - put - current - { checkingLegacyModuleStage = - Just stage' - , checkingTransitionModuleBuilder = - transitionBuilder' - } - -authorizeLegacyDeclaration - :: LegacyModuleStage - -> LegacyDeclarationReservation - -> [LegacyFactProducer] - -> [ResolvedObligationBatch] - -> CheckingM (NonEmpty H1LegacyAdmittedFact) -authorizeLegacyDeclaration stage reservation producers batches = do - established <- - traverse - (establishedLegacyObligation - (legacyStageModuleOrdinal stage)) - [ (batch, obligation) - | batch <- batches - , obligation <- - Vector.toList - (resolvedBatchObligations batch) - ] - let reserved = - NonEmpty.toList - (legacyReservedFacts reservation) - authorizationInputs = - zip producers reserved - admitted <- - traverse - (authorizeOne established) - authorizationInputs - case admitted of - firstAdmitted : remainingAdmitted -> - pure (firstAdmitted :| remainingAdmitted) - [] -> - impossible - "nonempty legacy reservation produced no admitted facts" - where - authorizeOne established (producer, reserved) = - case producer of - LegacyDeclaredAssumptionProducer kind -> - pure - (authorizeLegacyDeclaredAssumption - stage - kind - reserved) - LegacyDirectObligationProducer -> - case directLegacyAuthorization - reserved - batches - established of - Just admitted -> - pure admitted - Nothing -> - pure - (authorizeLegacyRule - (LegacyTheoremRule - LegacyOrdinaryTheoremFinalization) - (legacyEstablishedPredecessors - established) - (foldMap - establishedLegacyTrust - established) - reserved) - LegacyDeclarationRuleProducer tag -> - pure - (authorizeLegacyRule - tag - (legacyEstablishedPredecessors - established) - (foldMap - establishedLegacyTrust - established) - reserved) - -data EstablishedLegacyObligation = EstablishedLegacyObligation - !ResolvedObligation - !SessionLegacyObligationRef - !Marker - !(Vector LegacyFactRef) - !LegacyTrustDependencies - !LegacyTrustDependencies - -establishedLegacyTrust - :: EstablishedLegacyObligation - -> LegacyTrustDependencies -establishedLegacyTrust - (EstablishedLegacyObligation - _resolved - _reference - _marker - _factPredecessors - _predecessorTrust - trust) = - trust - -legacyEstablishedPredecessors - :: [EstablishedLegacyObligation] - -> Vector (LegacyRulePredecessor LegacyFactRef) -legacyEstablishedPredecessors established = - Vector.fromList - [ predecessor - | EstablishedLegacyObligation - _resolved - obligationReference - _marker - factReferences - _predecessorTrust - _trust <- - established - , predecessor <- - (legacyRuleFactPredecessor - <$> Vector.toList factReferences) - <> [ legacyRuleObligationPredecessor - obligationReference - ] - ] - -establishedLegacyObligation - :: LegacyModuleOrdinal - -> (ResolvedObligationBatch, ResolvedObligation) - -> CheckingM EstablishedLegacyObligation -establishedLegacyObligation moduleOrdinal (batch, resolved) = do - let prepared = - resolvedObligationPrepared resolved - ordinal = - preparedObligationOrdinal prepared - selected = - preparedObligationSelectedPremises prepared - expectedHypotheses = - taskHypotheses - (preparedObligationTask prepared) - unless - ( (preparedPremiseHypothesis - <$> Vector.toList selected) - == expectedHypotheses - ) - (throwIO - (LegacyPreparedPremiseSelectionMismatch - ordinal)) - (factReferences, predecessorTrust) <- - foldM - (collectPremise ordinal) - ([], mempty) - selected - let marker = - preparedBatchMarker - (resolvedBatchPrepared batch) - obligationReference = - sessionLegacyObligationRef - moduleOrdinal - marker - ordinal - trust = - case - ( resolvedObligationVampireRun resolved - , resolvedObligationGapLocation resolved - ) - of - (Just _accepted, Nothing) -> - legacyTrustedVampireTrust - obligationReference - predecessorTrust - (Nothing, Just gapLocation) -> - legacyGapTrust - obligationReference - gapLocation - marker - predecessorTrust - _ -> - impossible - "resolved legacy obligation has no evidence" - pure - (EstablishedLegacyObligation - resolved - obligationReference - marker - (Vector.fromList (reverse factReferences)) - predecessorTrust - trust) - where - collectPremise ordinal (references, trust) premise = - case preparedPremiseOrigin premise of - RegisteredLegacyFactPremise - reference - _origin - premiseTrust -> - pure - ( reference : references - , trust <> premiseTrust - ) - RegisteredFactPremise _origin -> - throwIO - (LegacyFactPremiseHasNoAuthorization - ordinal - (hypothesisMarker - (preparedPremiseHypothesis - premise))) - LocalHypothesisPremise{} -> - pure (references, trust) - -directLegacyAuthorization - :: LegacyReservedFact - -> [ResolvedObligationBatch] - -> [EstablishedLegacyObligation] - -> Maybe H1LegacyAdmittedFact -directLegacyAuthorization reserved batches established = - case (batches, established) of - ([batch], [establishedObligation]) - | Vector.length - (preparedBatchObligations - (resolvedBatchPrepared batch)) - == 1 - , directTarget batch establishedObligation - == reservedTarget -> - directFromEvidence establishedObligation - _ -> - Nothing - where - reservedTarget = - legacyPreparedFormula - (prepareLegacyProposition - (Facts.stagedFactSemantic - (legacyReservedStagedFact reserved))) - - directTarget batch - (EstablishedLegacyObligation - resolved - _reference - _marker - _facts - _predecessorTrust - _trust) = - forallClosure - mempty - (case localPremises of - [] -> - taskConjecture task - _ -> - makeConjunction localPremises - `Implies` taskConjecture task) - where - task = - preparedObligationTask - (resolvedObligationPrepared resolved) - localPremises = - reverse - [ hypothesisFormula - (preparedPremiseHypothesis premise) - | premise <- - Vector.toList - (preparedBatchPremises - (resolvedBatchPrepared batch)) - , LocalHypothesisPremise{} <- - [preparedPremiseOrigin premise] - ] - - directFromEvidence - (EstablishedLegacyObligation - resolved - reference - marker - _factReferences - predecessorTrust - _trust) = - case - ( resolvedObligationVampireRun resolved - , resolvedObligationGapLocation resolved - ) of - (Just accepted, Nothing) -> - Just - (authorizeLegacyTrustedVampire - reference - accepted - predecessorTrust - reserved) - (Nothing, Just gapLocation) -> - Just - (authorizeLegacyGap - reference - gapLocation - marker - predecessorTrust - reserved) - _ -> - Nothing - --- | Verification of a lemma with a proof. --- We skip omitted proofs and treat them as proper gaps of the formalization. --- This is useful when developing a formalization, as it makes it easy to --- leave difficult proofs for later. -checkLemmaWithProof - :: BlockContext - -> Lemma - -> Proof - -> Checking -checkLemmaWithProof context (Lemma asms goal) proof = do - committed <- prepareOrdinaryFactCommit context asms goal - locally do - registerLemmaLocalVars asms goal - registerAssumptionStructContexts asms - assume asms - setGoals [goal] - checkProof proof - putDeclarationCandidate committed - setDeclarationFactProducers - [LegacyDirectObligationProducer] - - --- | Verification of a lemma without a proof. -checkLemma :: BlockContext -> Lemma -> Checking -checkLemma context (Lemma asms goal) = do - staged <- - prepareOrdinaryStagedFact context asms goal - st <- get - case prepareTypedGroundReflexivity context staged st of - Nothing -> do - case prepareTypedAtomicReuse context staged st of - Nothing -> do - committed <- - either - throwIO - pure - (commitOrdinaryFact context staged st) - locally do - registerLemmaLocalVars asms goal - registerAssumptionStructContexts asms - assume asms - setGoals [goal] - tellTasks - putDeclarationCandidate committed - setDeclarationFactProducers - [LegacyDirectObligationProducer] - Just result -> do - committed <- - either throwIO pure result - putDeclarationCandidate committed - setDeclarationFactProducers [] - Just result -> do - committed <- - either throwIO pure result - putDeclarationCandidate committed - setDeclarationFactProducers [] - - -checkAxiom :: BlockContext -> Axiom -> Checking -checkAxiom context (Axiom asms axiom) = do - staged <- - prepareOrdinaryStagedFact context asms axiom - st <- get - case prepareTypedAtomicAssumption context staged st of - Nothing -> do - committed <- - either - throwIO - pure - (commitOrdinaryFact context staged st) - putDeclarationCandidate committed - setDeclarationFactProducers - [ LegacyDeclaredAssumptionProducer - DeclaredUserAxiom - ] - Just result -> do - committed <- - either throwIO pure result - putDeclarationCandidate committed - setDeclarationFactProducers [] - -prepareOrdinaryFactCommit - :: BlockContext - -> [Asm] - -> Formula - -> CheckingM CheckingState -prepareOrdinaryFactCommit context asms statement = do - staged <- - prepareOrdinaryStagedFact - context - asms - statement - st <- get - either - throwIO - pure - (commitOrdinaryFact context staged st) - -prepareOrdinaryStagedFact - :: BlockContext - -> [Asm] - -> Formula - -> CheckingM Facts.StagedFact -prepareOrdinaryStagedFact context asms statement = do - prepared <- - Facts.prepareSemanticFact - <$> canonicalizedFactWithAsms asms statement - pure - (stagePreparedFact - (blockContextLocation context) - (blockContextMarker context) - (blockContextMarker context) - prepared) - -prepareTypedGroundReflexivity - :: BlockContext - -> Facts.StagedFact - -> CheckingState - -> Maybe (Either CheckingError CheckingState) -prepareTypedGroundReflexivity context staged st = do - builder <- - checkingTransitionModuleBuilder st - prepared <- - TypedReflexivity.prepareGroundReflexivity - (Facts.preparedSemanticStatement - (Facts.stagedFactSemantic staged)) - pure do - typed <- - first - (checkingErrorAt context - . ("typed reflexivity preparation failed: " - <>) - . Text.pack - . show) - prepared - markers' <- - validatedMarkers - (blockContextLocation context) - [blockContextMarker context] - st - validatePreparedSemanticFact - context - (checkingOwnedSymbols st) - (checkingDependencies st) - (Facts.stagedFactSemantic staged) - builder' <- - first - (checkingErrorAt context - . ("typed reflexivity admission failed: " - <>) - . Text.pack - . show) - (Transition.commitTransitionKernelFact - (blockContextMarker context :| []) - (Transition.origin - (blockContextLocation context) - Nothing - (Just - (blockContextMarker context))) - (TypedReflexivity.groundReflexivityTarget - typed) - (TypedReflexivity.groundReflexivityDerivation - typed) - builder) - pure - st - { definedMarkers = markers' - , blockLabel = - blockContextMarker context - , stepLocation = - blockContextLocation context - , checkingHypothesisCounter = 0 - , checkingTransitionModuleBuilder = - Just builder' - } - -prepareTypedAtomicAssumption - :: BlockContext - -> Facts.StagedFact - -> CheckingState - -> Maybe (Either CheckingError CheckingState) -prepareTypedAtomicAssumption context staged st = do - builder <- - checkingTransitionModuleBuilder st - preparation <- - TypedAtomic.prepareClosedAtomic - (`Transition.lookupTransitionGlobal` builder) - (Facts.preparedSemanticStatement - (Facts.stagedFactSemantic staged)) - pure do - prepared <- - first - (typedFactError - context - "typed atomic preparation failed: ") - preparation - markers' <- - validateTypedFactState - context - staged - st - builder' <- - first - (typedFactError - context - "typed declared-assumption registration failed: ") - (Transition.commitTransitionTypedDeclaredAssumption - (blockContextMarker context :| []) - (typedFactOrigin context) - DeclaredUserAxiom - (TypedAtomic.closedAtomicStatement - prepared) - builder) - pure - (publishTypedFactState - context - markers' - builder' - st) - -prepareTypedAtomicReuse - :: BlockContext - -> Facts.StagedFact - -> CheckingState - -> Maybe (Either CheckingError CheckingState) -prepareTypedAtomicReuse context staged st = do - builder <- - checkingTransitionModuleBuilder st - preparation <- - TypedAtomic.prepareClosedAtomic - (`Transition.lookupTransitionGlobal` builder) - (Facts.preparedSemanticStatement - (Facts.stagedFactSemantic staged)) - case preparation of - Left err -> - Just - (Left - (typedFactError - context - "typed atomic preparation failed: " - err)) - Right prepared -> do - let target = - TypedAtomic.closedAtomicStatement - prepared - case Transition.lookupTransitionTypedImport - target - builder of - Left err -> - Just - (Left - (typedFactError - context - "typed import lookup failed: " - err)) - Right Nothing -> - Nothing - Right (Just imported) -> - pure do - markers' <- - validateTypedFactState - context - staged - st - builder' <- - first - (typedFactError - context - "typed imported-fact admission failed: ") - (Transition.commitTransitionKernelFactWithImports - (blockContextMarker context :| []) - (typedFactOrigin context) - (Vector.singleton imported) - target - (importedFactDerivation - (importIx 0)) - builder) - pure - (publishTypedFactState - context - markers' - builder' - st) - -validateTypedFactState - :: BlockContext - -> Facts.StagedFact - -> CheckingState - -> Either CheckingError (HashSet Marker) -validateTypedFactState context staged st = do - markers' <- - validatedMarkers - (blockContextLocation context) - [blockContextMarker context] - st - validatePreparedSemanticFact - context - (checkingOwnedSymbols st) - (checkingDependencies st) - (Facts.stagedFactSemantic staged) - pure markers' - -publishTypedFactState - :: BlockContext - -> HashSet Marker - -> Transition.TransitionModuleBuilder - -> CheckingState - -> CheckingState -publishTypedFactState context markers' builder st = - st - { definedMarkers = markers' - , blockLabel = - blockContextMarker context - , stepLocation = - blockContextLocation context - , checkingHypothesisCounter = 0 - , checkingTransitionModuleBuilder = - Just builder - } - -typedFactOrigin - :: BlockContext - -> Transition.Origin -typedFactOrigin context = - Transition.origin - (blockContextLocation context) - Nothing - (Just - (blockContextMarker context)) - -typedFactError - :: Show error - => BlockContext - -> Text - -> error - -> CheckingError -typedFactError context prefix = - checkingErrorAt context - . (prefix <>) - . Text.pack - . show - --- | Validate and commit one ordinary axiom or proven fact. -commitOrdinaryFact - :: BlockContext - -> Facts.StagedFact - -> CheckingState - -> Either CheckingError CheckingState -commitOrdinaryFact context staged st = do - markers' <- - validatedMarkers location [marker] st - validatePreparedSemanticFact - context - (checkingOwnedSymbols st) - (checkingDependencies st) - (Facts.stagedFactSemantic staged) - facts' <- - first - (DuplicateMarker location) - (Facts.registerStagedFacts - (staged :| []) - (checkingFacts st)) - pure - st - { checkingFacts = facts' - , definedMarkers = markers' - , blockLabel = marker - , stepLocation = location - } - where - location = - blockContextLocation context - marker = - blockContextMarker context - -checkProof :: Proof -> Checking -checkProof = \case - Qed mloc j -> do - loc <- case mloc of - Just loc -> pure loc - Nothing -> do - gets blockEndLocation - setLocation loc - justify j - Contradiction loc j -> do - setLocation loc - setGoals [Bottom] - justify j - ByContradiction loc proof -> do - setLocation loc - goals <- gets checkingGoals - case goals of - [goal] -> do - assume [Asm (Not loc goal)] - modify \st -> - st - { checkingGoals = [Bottom] - , checkingDirectness = Indirect goal - } - checkProof proof - _ -> throwWithLocationAndMarker (ByContradictionOnMultipleGoals) - ByCase loc splits -> do - setLocation loc - for_ splits \(Case split _) -> - assertKnownFormulaVars "case split" split - for_ splits checkCase - setGoals [makeDisjunction (caseOf <$> splits)] - tellTasks - BySetInduction loc mx continue -> do - setLocation loc - goals <- gets checkingGoals - case goals of - Forall scope : goals' -> do - let zs = nubOrd (bindings scope) - z <- case mx of - Nothing -> case zs of - [z'] -> pure z' - _ -> throwWithMarker (AmbiguousInductionVar loc) - Just (TermVar z') -> pure z' - _ -> throwWithMarker (AmbiguousInductionVar loc) - checkFreshLocalVars "set induction" [z] - let y = NamedVar "IndAntecedent" - let ys = List.delete z zs - let anteInst bv = if bv == z then TermVar y else TermVar bv - let antecedent = makeForall (y : ys) ((isElementOf (TermVar y) (TermVar z)) `Implies` instantiate anteInst scope) - addLocalVars (Set.singleton z) - assume [Asm antecedent] - let consequent = instantiate TermVar scope - setGoals (consequent : goals') - checkProof continue - _ -> throwWithMarker (BySetInductionSyntacticMismatch loc) - ByOrdInduction loc continue -> do - setLocation loc - goals <- gets checkingGoals - case goals of - Forall scope : goals' -> case fromScope scope of - Implies (IsOrd loc' (TermVar (B _))) rhs -> do - let zs = nubOrd (bindings scope) - z <- case zs of - [z'] -> pure z' - _ -> throwWithMarker (AmbiguousInductionVar loc') - checkFreshLocalVars "ordinal induction" [z] - -- LATER: this is kinda sketchy: - -- we now use the induction variable in two ways: - -- we assume the induction hypothesis, where we recycle the induction variable both as a bound variable and a free variable - -- we then need to show that under that hypothesis the claim holds for the free variable... - let hypo = Forall (toScope (Implies (isElementOf (TermVar (B z)) (TermVar (F z))) rhs)) - addLocalVars (Set.singleton z) - assume [Asm (IsOrd loc' (TermVar z)), Asm hypo] - let goal' = unvar id id <$> rhs -- we "instantiate" the single bound variable on the rhs - setGoals (goal' : goals') - checkProof continue - _ -> - throwWithMarker - (ByOrdInductionSyntacticMismatch loc) - _ -> - throwWithMarker - (ByOrdInductionSyntacticMismatch loc) - Assume loc phi continue -> do - setLocation loc - assertKnownFormulaVars "assumption step" phi - goals' <- matchAssumptionWithGoal loc phi - assume [Asm phi] - setGoals goals' - checkProof continue - Fix loc xs suchThat continue -> do - setLocation loc - checkFreshLocalVars "fix step" (toList xs) - fixing xs - addLocalVars (Set.fromList (toList xs)) - unless (suchThat == Top) do - assertKnownFormulaVars "fix constraint" suchThat - checkProof case suchThat of - Top -> continue - _ -> Assume loc suchThat continue - Subclaim loc subclaim subproof continue -> do - setLocation loc - assertKnownFormulaVars "subclaim" subclaim - context <- - BlockContext - <$> gets stepLocation - <*> gets blockLabel - locally - (checkLemmaWithProof - context - (Lemma [] subclaim) - subproof) - assume [Asm subclaim] - checkProof continue - Omitted loc -> do - setLocation loc - omitCurrentGoals loc - Suffices loc reduction by proof -> do - setLocation loc - assertKnownFormulaVars "suffices step" reduction - goals <- gets checkingGoals - setGoals [reduction `Implies` makeConjunction goals] - justify by - setGoals [reduction] - checkProof proof - Take loc _witnesses _suchThat JustificationSetExt _continue -> do - setLocation loc - throwWithLocationAndMarker SetExtensionalityWithTake - Take loc witnesses suchThat by continue -> locally do - setLocation loc - checkFreshLocalVars "take step" (toList witnesses) - known <- gets localVars - assertKnownFormulaVarsWith "take witness statement" (known <> Set.fromList (toList witnesses)) suchThat - goals <- gets checkingGoals - setGoals [makeExists witnesses suchThat] - justify by - addLocalVars (Set.fromList (toList witnesses)) - assume [Asm suchThat] - setGoals goals - checkProof continue - Have loc claim (JustificationRef ms) continue -> locally do - setLocation loc - assertKnownFormulaVars "claim" claim - goals <- gets checkingGoals - setGoals [claim] - byRef ms -- locally prove things with just refs and local assumptions - assume [Asm claim] - setGoals goals - checkProof continue - Have loc claim JustificationLocal continue -> locally do - setLocation loc - assertKnownFormulaVars "claim" claim - goals <- gets checkingGoals - setGoals [claim] - byAssumption -- locally prove things with just local assumptions - assume [Asm claim] - setGoals goals - checkProof continue - Have loc claim by continue -> do - setLocation loc - assertKnownFormulaVars "claim" claim - locally do - goals <- gets checkingGoals - claims <- case by of - JustificationEmpty -> - pure [claim] - JustificationSetExt -> - splitGoalWithSetExt claim - -- NOTE: we already handled @JustificationRef ms@ and GHC recognizes this - setGoals claims - tellTasks - assume [Asm claim] - setGoals goals - checkProof continue - Define loc x t continue -> locally do - setLocation loc - checkFreshLocalVars "definition step" [x] - assertKnownTermVars "definition right-hand side" t - addLocalVars (Set.singleton x) - case t of - TermSep y yBound phi -> - assume [Asm $ - makeForall [y] $ - Iff (isElementOf (TermVar y) (TermVar x)) - ((isElementOf (TermVar y) yBound) `And` instantiate1 (TermVar y) phi) - ] - ReplacePred _y _x xBound scope -> do - goals <- gets checkingGoals - let x' = FreshVar 0 - let y = FreshVar 1 - let y' = FreshVar 2 - let fromReplacementVar = \case - ReplacementDomVar -> TermVar x' - ReplacementRangeVar -> TermVar y - let fromReplacementVar' = \case - ReplacementDomVar -> TermVar x' - ReplacementRangeVar -> TermVar y' - let phi = instantiate fromReplacementVar scope - let psi = instantiate fromReplacementVar' scope - let singleValued = - makeForall [x'] $ - (TermVar x' `isElementOf` xBound) `Implies` - makeForall [y, y'] (((phi `And` psi) `Implies` (TermVar y `equals` TermVar y'))) - setGoals [singleValued] - tellTasks - - -- Now we restore the goals, which should already be canonical, so we don't need to canonicalize them again. - modify (\st -> st{checkingGoals = goals}) - assume [Asm $ - makeForall [y] $ - (TermVar y `isElementOf` TermVar x) - `Iff` - makeExists [x'] ((TermVar x' `isElementOf` xBound) `And` phi) - ] - ReplaceFun bounds lhs cond -> - assume [Asm (makeReplacementIff (TermVar (F x)) bounds lhs cond)] - _ -> - assume [Asm (Equals loc (TermVar x) t)] - checkProof continue - DefineFunction loc funVar argVar valueExpr domExpr continue -> do - setLocation loc - checkFreshLocalVars "function definition" [funVar] - checkBinderVarsFresh "function definition" [argVar] - when (funVar == argVar) do - throwCheckingError "function definition uses the same variable for the function and its argument" - known <- gets localVars - assertKnownTermVarsWith "function definition domain" known domExpr - assertKnownTermVarsWith "function definition value" (Set.insert argVar known) valueExpr - addLocalVars (Set.singleton funVar) - -- we're given f, x, e, d - assume - [ Asm (Equals loc (TermOp Nowhere DomSymbol [TermVar funVar]) domExpr) -- dom(f) = d - , Asm (makeForall [argVar] ((isElementOf (TermVar argVar) domExpr) `Implies` (Equals Nowhere (TermOp Nowhere ApplySymbol [TermVar funVar, TermVar argVar]) valueExpr))) -- f(x) = e for all x\in d - , Asm (rightUniqueAdj loc (TermVar funVar)) - , Asm (relationNoun loc (TermVar funVar)) - ] - checkProof continue - Calc loc quant calc continue -> do - setLocation loc - for_ (calculation quant calc) \(goal, _) -> - assertKnownFormulaVars "calculation step" goal - assertKnownFormulaVars "calculation result" (calcResult quant calc) - checkCalc quant calc - assume [Asm (calcResult quant calc)] - checkProof continue - DefineFunctionLocal loc funVar argVar domVar ranExpr definitions continue -> do -- TODO refactor - setLocation loc - checkFreshLocalVars "local function definition" [funVar] - checkBinderVarsFresh "local function definition" [argVar] - when (funVar == argVar) do - throwCheckingError "local function definition uses the same variable for the function and its argument" - known <- gets localVars - assertKnownFormulaVarsWith "local function definition range" known ranExpr - let knownWithArg = Set.insert argVar known - for_ definitions \(expr, frm) -> do - assertKnownTermVarsWith "local function definition case expression" knownWithArg expr - assertKnownFormulaVarsWith "local function definition case condition" knownWithArg frm - unless (domVar `Set.member` known) do - throwCheckingError ("local function definition domain variable is not in scope: " <> formatVars (Set.singleton domVar)) - addLocalVars (Set.singleton funVar) - -- We have f: X \to Y and x \mapsto ... - -- definition is a nonempty list of (expresssion e, formula phi) - -- such that f(x) = e if phi(x) - -- since we do a case deduction in the definition there has to be a check that, - -- our domains in the case are a disjunct union of dom(f) - assume - [Asm (Equals Nowhere (TermOp Nowhere DomSymbol [TermVar funVar]) (TermVar domVar)) - ,Asm (rightUniqueAdj Nowhere (TermVar funVar)) - ,Asm (relationNoun Nowhere (TermVar funVar))] - - goals <- gets checkingGoals - setGoals [makeForall [argVar] ((isElementOf (TermVar argVar) (TermVar domVar)) `Iff` localFunctionGoal definitions)] - tellTasks - - locals <- gets localVars - assume [Asm (makeForall [argVar] (isElementOf (TermVar argVar) (TermVar domVar) `Implies` isElementOf (TermOp Nowhere ApplySymbol [TermVar funVar, TermVar argVar]) ranExpr))] -- function f from \dom(f) \to \ran(f) - assume (functionSubdomianExpression funVar argVar domVar locals (NonEmpty.toList definitions)) --behavior on the subdomians - setGoals goals - checkProof continue - --- |Creats the Goal \forall x. x \in dom{f} \iff (phi_{1}(x) \xor (\phi_{2}(x) \xor (... \xor (\phi_{n}) ..))) --- where the phi_{i} are the subdomain statments -localFunctionGoal :: NonEmpty (Term,Formula) -> Formula -localFunctionGoal xs = makeXor $ map snd $ NonEmpty.toList xs - - --- We have our list of expr and forumlas, in this case normaly someone would write --- f(x) = ....cases --- & (\frac{1}{k} \cdot x) &\text{if} x \in \[k, k+1\) --- --- since we have to bind all globaly free Varibels we generate following asumptions. --- --- For x \mapsto expr(x,ys,cs) , if formula(x,ys) ; here cs are just global constants --- -> \forall x,ys: ( formula(x,ys) => expr(x,ys,cs)) - - -functionSubdomianExpression :: VarSymbol -> VarSymbol -> VarSymbol -> Set VarSymbol -> [(Term, Formula)] -> [Asm] -functionSubdomianExpression f a d s (x:xs) = singleFunctionSubdomianExpression f a d s x : functionSubdomianExpression f a d s xs -functionSubdomianExpression _ _ _ _ [] = [] - -singleFunctionSubdomianExpression :: VarSymbol -> VarSymbol -> VarSymbol -> Set VarSymbol -> (Term, Formula) -> Asm -singleFunctionSubdomianExpression funVar argVar domVar fixedV (expr, frm) = let - -- boundVar = Set.toList (freeVars expr) in - -- let def = makeForall (argVar:boundVar) (((TermVar argVar `IsElementOf` TermVar domVar) `And` frm) `Implies` TermOp ApplySymbol [TermVar funVar, TermVar argVar] `Equals` expr) - boundVar = fixedV in - let def = forallClosure boundVar (((isElementOf (TermVar argVar) (TermVar domVar)) `And` frm) `Implies` Equals Nowhere (TermOp Nowhere ApplySymbol [TermVar funVar, TermVar argVar]) expr) - in Asm def - - - -checkCalc :: CalcQuantifier -> Calc -> Checking -checkCalc quant calc = locally do - let tasks = calculation quant calc - forM_ tasks tell - where - tell = \case - (goal, by) -> setGoals [goal] *> justify by - - -makeReplacementIff - :: forall a. (ExprOf (Var VarSymbol a) -- ^ Newly defined local constant. - -> NonEmpty (VarSymbol, ExprOf a) -- ^ Bounds of the replacement. - -> Scope VarSymbol ExprOf a -- ^ Left hand side (function application). - -> Scope VarSymbol ExprOf a -- ^ Optional constraints on bounds (can just be 'Top'). - -> ExprOf a) -makeReplacementIff e bounds lhs cond = - Forall (toScope (Iff (isElementOf (TermVar (B "frv")) e) existsPreimage)) - where - existsPreimage :: ExprOf (Var VarSymbol a) - existsPreimage = Exists (toScope replaceBound) - - replaceBound :: ExprOf (Var VarSymbol (Var VarSymbol a)) - replaceBound = makeConjunction [isElementOf (TermVar (B x)) (F . F <$> xB) | (x, xB) <- toList bounds] `And` replaceCond - - replaceEq :: ExprOf (Var VarSymbol (Var VarSymbol a)) - replaceEq = Equals Nowhere (nestF <$> fromScope lhs) (TermVar (F (B "frv"))) - - replaceCond :: ExprOf (Var VarSymbol (Var VarSymbol a)) - replaceCond = case fromScope cond of - Top -> replaceEq - cond' -> replaceEq `And` (nestF <$> cond') - - nestF :: Var b a1 -> Var b (Var b1 a1) - nestF (B a) = B a - nestF (F a) = F (F a) - - -splitGoalWithSetExt :: Formula -> CheckingM [Formula] -splitGoalWithSetExt = \case - NotEquals loc x y -> do - let z = FreshVar 0 - elemNotElem x' y' = makeExists [FreshVar 0] (And (IsElementOf loc (TermVar z) x') (isNotElementOf loc (TermVar z) y')) - pure [elemNotElem x y `Or` elemNotElem y x] - Equals loc x y -> do - let z = FreshVar 0 - subset x' y' = makeForall [FreshVar 0] (Implies (IsElementOf loc (TermVar z) x') (IsElementOf loc (TermVar z) y')) - pure [subset x y, subset y x] - goal -> throwWithLocationAndMarker (MismatchedSetExt [goal]) - -justify :: Justification -> Checking -justify = \case - JustificationEmpty -> tellTasks - JustificationLocal -> byAssumption - JustificationRef ms -> byRef ms - JustificationSetExt -> do - goals <- gets checkingGoals - case goals of - [goal] -> do - goals' <- splitGoalWithSetExt goal - setGoals goals' - tellTasks - _ -> throwWithLocationAndMarker (MismatchedSetExt goals) - -byRef :: NonEmpty Marker -> Checking -byRef ms = locally do - facts <- gets checkingFacts - dumpPremselTraining <- gets checkingDumpPremselTraining - case dumpPremselTraining of - WithDumpPremselTraining -> dumpTrainingData facts ms - WithoutDumpPremselTraining -> skip - case Facts.restrictFactRegistry ms facts of - Left (Marker str) -> - throwWithLocationAndMarker - (CheckingError ("unknown marker: " <> str)) - Right facts' -> modify (\st -> st{checkingFacts = facts'}) *> tellTasks - -byAssumption :: Checking -byAssumption = locally do - modify (\st -> st{checkingFacts = Facts.emptyFactRegistry}) *> tellTasks - -dumpTrainingData :: Facts.FactRegistry -> NonEmpty Marker -> Checking -dumpTrainingData facts ms = do - (picked, unpicked) <- - case Facts.partitionFactRegistry ms facts of - Left (Marker str) -> - throwWithLocationAndMarker - (CheckingError ("unknown marker: " <> str)) - Right partitioned -> - pure partitioned - goals <- gets checkingGoals - Marker m_ <- gets blockLabel - let dir = "premseldump" - let makePath k = dir </> (Text.unpack m_ <> show (k :: Int)) <.> "txt" - dumpTrainingExample goal = - let prepared = - prepareTrainingTptpTask - goal - (factHypotheses picked) - (factHypotheses unpicked) - k = hash goal - example = preparedTptpTextNewline prepared - in do - liftIO (Text.writeFile (makePath k) example) - liftIO (createDirectoryIfMissing True dir) - forM_ goals dumpTrainingExample - --- | Since the case tactic replaces /all/ current goals with the disjunction --- of the different case hypotheses, each case proof must cover all goals. -checkCase :: Case -> Checking -checkCase (Case split proof) = locally do - assume [Asm split] - checkProof proof - - -checkDefn :: BlockContext -> Defn -> Checking -checkDefn context defn = do - let (ownerKind, definedSymbol, definitionAsms, definiens) = definitionParts defn - dependencies <- checkedDefinitionDependencies definedSymbol definitionAsms definiens - (prepared, soundnessGoals) <- prepareDefinitionFact context defn - let staged = - stagePreparedFact - (blockContextLocation context) - (blockContextMarker context) - (blockContextMarker context) - prepared - st <- get - committed <- - either - throwIO - pure - (commitDefinition - context - ownerKind - definedSymbol - dependencies - staged - st) - unless (null soundnessGoals) do - locally do - modify \current -> - current{checkingGoals = soundnessGoals} - tellTasks - putDeclarationCandidate committed - setDeclarationFactProducers - [ LegacyDeclarationRuleProducer - (LegacyDefinitionRule - LegacyDefinitionEquation) - ] - -prepareDefinitionFact - :: BlockContext - -> Defn - -> CheckingM (Facts.PreparedSemanticFact, [Formula]) -prepareDefinitionFact context = \case - DefnPredicate asms symb vs f -> do - -- We first need to take the universal closure of the defining formula - -- while ignoring the variables that occur on the lhs, then take the - -- universal formula of the equivalence, quantifying the remaining - -- variables (from the lhs). - let vs' = TermVar <$> toList vs - let f' = forallClosure (Set.fromList (toList vs)) f - prepared <- - prepareWithAsms - asms - (Atomic location symb vs' `Iff` f') - pure (prepared, []) - DefnFun asms fun vs rhs -> do - let lhs = - TermSymbol location (SymbolFun fun) (TermVar <$> vs) - prepared <- - prepareWithAsms asms (Equals location lhs rhs) - pure (prepared, []) - DefnOp op vs (TermSep x bound phi) -> do - let generated = - makeForall (x : vs) $ - Iff (TermVar x `isElementOf` TermOp location op (TermVar <$> vs)) - ((TermVar x `isElementOf` bound) `And` instantiate1 (TermVar x) phi) - prepared <- prepare generated - pure (prepared, []) - DefnOp op vs (TermSymbol _pos rhsSymbol [x, y]) | rhsSymbol == SymbolMixfix ConsSymbol -> do - -- TODO generalize this to support arbitrarily many applications of _Cons - -- and also handle the case of emptyset or singleton as final argument separately - -- so that finite set terms get recognized in full. - let phi = - isElementOf - (TermVar "any") - (TermOp location op (TermVar <$> vs)) - let psi = - (isElementOf (TermVar "any") y) - `Or` (Equals location (TermVar "any") x) - prepared <- - prepare (makeForall ("any" : vs) (phi `Iff` psi)) - pure (prepared, []) - DefnOp op vs (ReplacePred _y _x xBound scope) -> do - let x = (FreshVar 0) - let y = (FreshVar 1) - let y' = (FreshVar 2) - let fromReplacementVar = \case - ReplacementDomVar -> TermVar x - ReplacementRangeVar -> TermVar y - let fromReplacementVar' = \case - ReplacementDomVar -> TermVar x - ReplacementRangeVar -> TermVar y' - let phi = instantiate fromReplacementVar scope - let psi = instantiate fromReplacementVar' scope - let singleValued = makeForall [x] ((TermVar x `isElementOf` xBound) `Implies` makeForall [y, y'] ((phi `And` psi) `Implies` (TermVar y `equals` TermVar y'))) - let generated = - makeForall (y : vs) - ((TermVar y `isElementOf` TermOp Nowhere op (TermVar <$> vs)) - `Iff` - makeExists [x] ((TermVar x `isElementOf` xBound) `And` phi)) - preparedGoal <- canonicalize singleValued - prepared <- prepare generated - pure (prepared, [preparedGoal]) - DefnOp op vs (ReplaceFun bounds lhs cond) -> do - let generated = forallClosure mempty (makeReplacementIff (TermOp Nowhere op (TermVar . F <$> vs)) bounds lhs cond) - prepared <- prepare generated - pure (prepared, []) - DefnOp op vs rhs -> - if containsHigherOrderConstructs rhs - then - throwIO - (CouldNotEliminateHigherOrder - op - rhs - location - (blockContextMarker context)) - else do - let lhs = TermSymbol Nowhere (SymbolMixfix op) (TermVar <$> vs) - prepared <- - prepareWithAsms [] (Equals Nowhere lhs rhs) - pure (prepared, []) - where - location = - blockContextLocation context - - prepare formula = - Facts.prepareSemanticFact <$> canonicalize formula - - prepareWithAsms asms formula = - Facts.prepareSemanticFact - <$> canonicalizedFactWithAsms asms formula - --- | Validate and commit every state row introduced by one definition. -commitDefinition - :: BlockContext - -> SymbolOwnerKind - -> Symbol - -> Set Symbol - -> Facts.StagedFact - -> CheckingState - -> Either CheckingError CheckingState -commitDefinition context ownerKind symbol dependencies staged st = do - markers' <- - validatedMarkers location [marker] st - validateOwnedDependenciesAt - context - (checkingOwnedSymbols st) - dependencies - (owners', ownedMarkers', dependencies') <- - validatedSymbolRegistration - context - ownerKind - symbol - dependencies - st - validatePreparedSemanticFact - context - owners' - dependencies' - (Facts.stagedFactSemantic staged) - facts' <- - first - (DuplicateMarker location) - (Facts.registerStagedFacts - (staged :| []) - (checkingFacts st)) - pure - st - { checkingFacts = facts' - , checkingDependencies = dependencies' - , checkingOwnedSymbols = owners' - , checkingOwnedSymbolMarkers = ownedMarkers' - , definedMarkers = markers' - , blockLabel = marker - , stepLocation = location - , checkingHypothesisCounter = 0 - } - where - location = - blockContextLocation context - marker = - blockContextMarker context - - -checkSig :: BlockContext -> [Asm] -> Signature -> Checking -checkSig context asms signature = do - (ownerKind, symbol, staged, typedCoreType) <- case signature of - SignatureFormula formula -> do - symbol <- - maybe - (throwIO - (checkingErrorAt - context - "could not recover the declared symbol from SignatureFormula")) - pure - (recoverSignatureFormulaSymbol formula) - prepared <- - Facts.prepareSemanticFact - <$> canonicalizedFactWithAsms asms formula - pure - ( OwnedBySignatureFormula - , symbol - , Just - (stagePreparedFact - (blockContextLocation context) - (blockContextMarker context) - (blockContextMarker context) - prepared) - , Nothing - ) - SignaturePredicate predicate variables -> - pure - ( OwnedBySignaturePredicate - , SymbolPredicate predicate - , Nothing - , Just - (foldr - Core.TyArrow - Core.TyProp - (replicate - (length variables) - Core.TySet)) - ) - st <- get - committed <- - either - throwIO - pure - (commitSignature context ownerKind symbol staged st) - transitionBuilder' <- - case typedCoreType of - Nothing -> - pure - (checkingTransitionModuleBuilder - committed) - Just coreType -> - traverse - (either - (throwIO - . checkingErrorAt - context - . ("typed signature registration failed: " - <>) - . Text.pack - . show) - pure - . Transition.commitTransitionOpaqueGlobal - symbol - coreType - (Transition.origin - (blockContextLocation context) - Nothing - (Just - (blockContextMarker - context)))) - (checkingTransitionModuleBuilder - committed) - putDeclarationCandidate - committed - { checkingTransitionModuleBuilder = - transitionBuilder' - } - setDeclarationFactProducers - (case staged of - Nothing -> - [] - Just _ -> - [ LegacyDeclaredAssumptionProducer - OpaqueAssumption - ]) - --- | Validate and commit every state row introduced by one signature. -commitSignature - :: BlockContext - -> SymbolOwnerKind - -> Symbol - -> Maybe Facts.StagedFact - -> CheckingState - -> Either CheckingError CheckingState -commitSignature context ownerKind symbol staged st = do - markers' <- - validatedMarkers location [marker] st - (owners', ownedMarkers', dependencies') <- - validatedSymbolRegistration - context - ownerKind - symbol - mempty - st - facts' <- - case staged of - Nothing -> - Right (checkingFacts st) - Just fact -> do - validatePreparedSemanticFact - context - owners' - dependencies' - (Facts.stagedFactSemantic fact) - first - (DuplicateMarker location) - (Facts.registerStagedFacts - (fact :| []) - (checkingFacts st)) - pure - st - { checkingFacts = facts' - , checkingDependencies = dependencies' - , checkingOwnedSymbols = owners' - , checkingOwnedSymbolMarkers = ownedMarkers' - , definedMarkers = markers' - , blockLabel = marker - , stepLocation = location - , checkingHypothesisCounter = 0 - } - where - location = - blockContextLocation context - marker = - blockContextMarker context - -recoverSignatureFormulaSymbol :: Formula -> Maybe Symbol -recoverSignatureFormulaSymbol = \case - Forall scope - | [boundVar] <- nubOrd (bindings scope) -> - case fromScope scope of - Equals _ (TermVar (B lhsVar)) (TermSymbol _ symbol@(SymbolMixfix _) _args) `Implies` _ - | lhsVar == boundVar -> - Just symbol - _ -> - Nothing - | otherwise -> - Nothing - _ -> - Nothing - -mergeAssumptions :: [Asm] -> CheckingM ([Formula], StructContext) -mergeAssumptions asms = do - ctx <- assumptionStructContext asms - phis <- traverse asmFormula asms - pure (phis, ctx) - -asmFormula :: Asm -> CheckingM Formula -asmFormula = \case - Asm phi -> - pure phi - AsmStruct x phrase -> - pure (structPredicate x phrase) - -canonicalize :: Formula -> CheckingM Formula -canonicalize phi = do - ctx <- gets checkingStructContext - canonicalizeWith ctx phi - --- | Canonicalize using an explicit structure context instead of the checker state's current one. -canonicalizeWith :: StructContext -> Formula -> CheckingM Formula -canonicalizeWith ctx phi = do - blockContext <- - BlockContext - <$> gets stepLocation - <*> gets blockLabel - canonicalizeWithAt blockContext ctx phi - -canonicalizeWithAt - :: BlockContext - -> StructContext - -> Formula - -> CheckingM Formula -canonicalizeWithAt blockContext ctx phi = do - phi' <- unabbreviate phi - desugarComprehensionsAt - blockContext - (annotateWithStructContext ctx phi') - -annotateWithStructContext :: StructContext -> Formula -> Formula -annotateWithStructContext StructContext{..} = - annotateWith structContextLabels structContextOps - -unabbreviate :: ExprOf a -> CheckingM (ExprOf a) -unabbreviate phi = do - abbrs <- gets checkingAbbreviations - pure (unabbreviateWith ((absurd <$>) <$> abbrs) phi) - - -data CheckedInductive = CheckedInductive - { checkedInductiveSymbol :: FunctionSymbol - , checkedInductiveParams :: [VarSymbol] - , checkedInductiveDomain :: Expr - , checkedInductiveIntros :: NonEmpty CheckedInductiveIntro - } - -data CheckedInductiveIntro = CheckedInductiveIntro - { checkedInductiveIntroVars :: [VarSymbol] - , checkedInductiveIntroConditions :: [CheckedInductiveCondition] - , checkedInductiveIntroResultTerm :: Term - } - -data CheckedInductiveCondition - = CheckedInductiveSideCondition Formula - | CheckedInductiveRecursiveCondition - { checkedInductiveRecursiveTerm :: Term - , checkedInductiveRecursiveCarrierTemplate :: Scope VarSymbol ExprOf VarSymbol - , checkedInductiveRecursiveDirect :: Bool - } - -checkInductive :: BlockContext -> Inductive -> Checking -checkInductive context inductive = do - st <- get - either - throwIO - pure - (validateInductiveHeader - context - (SymbolMixfix (inductiveSymbol inductive)) - st) - checked <- normalizeInductive inductive - case checkingTransitionModuleBuilder st of - Nothing -> - checkLegacyInductive context checked st - Just builder -> - checkTypedInductive - context - checked - builder - st - -checkLegacyInductive - :: BlockContext - -> CheckedInductive - -> CheckingState - -> Checking -checkLegacyInductive context checked st = do - soundnessGoals <- - traverse canonicalize (inductiveSoundnessGoals checked) - stagedFacts <- - traverse - (\(factMarker, formula) -> do - canonical <- canonicalize formula - pure - (stagePreparedFact - (blockContextLocation context) - (blockContextMarker context) - factMarker - (Facts.prepareSemanticFact canonical))) - (inductiveFacts - (blockContextMarker context) - checked) - committed <- - either - throwIO - pure - (commitInductive - context - checked - stagedFacts - st) - unless (null soundnessGoals) do - locally do - modify \current -> - current{checkingGoals = soundnessGoals} - tellTasks - putDeclarationCandidate committed - setDeclarationFactProducers - ( LegacyDeclarationRuleProducer - . LegacyInductiveRule - <$> inductiveFactRoles checked - ) - -checkTypedInductive - :: BlockContext - -> CheckedInductive - -> Transition.TransitionModuleBuilder - -> CheckingState - -> Checking -checkTypedInductive context checked builder st = do - direct <- - either - throwIO - pure - (directInductive context checked) - prepared <- - either - ( throwIO - . typedInductiveError - context - "typed inductive preparation failed: " - ) - pure - (TypedInductive.prepareTypedInductive - Transition.checkedGlobalType - (Transition.transitionBuilderFoundation - builder) - (typedSourceGlobal builder) - (blockContextMarker context) - direct) - imports <- - Vector.fromList - <$> traverse - (uncurry - (typedInductiveGuardImport - context - builder)) - (zip - [1 :: Int ..] - (Vector.toList - (TypedInductive.typedInductiveGuardTargets - prepared))) - builderWithCarrier <- - either - ( throwIO - . typedInductiveError - context - "typed inductive carrier registration failed: " - ) - pure - (Transition.commitTransitionTransparentGlobal - (SymbolMixfix - (checkedInductiveSymbol checked)) - (TypedInductive.typedInductiveCarrierType - prepared) - (TypedInductive.typedInductiveCarrierBody - prepared) - (typedFactOrigin context) - builder) - builder' <- - foldM - (commitTypedInductiveFact - context - imports) - builderWithCarrier - (TypedInductive.typedInductiveFacts - prepared) - committed <- - either - throwIO - pure - (commitTypedInductiveState - context - checked - (TypedInductive.typedInductiveFactMarker - <$> TypedInductive.typedInductiveFacts - prepared) - builder' - st) - putDeclarationCandidate committed - setDeclarationFactProducers [] - -directInductive - :: BlockContext - -> CheckedInductive - -> Either CheckingError TypedInductive.DirectInductive -directInductive context checked = - TypedInductive.DirectInductive - (checkedInductiveParams checked) - (checkedInductiveDomain checked) - <$> traverse directClause - (checkedInductiveIntros checked) - where - directClause intro = - TypedInductive.DirectInductiveClause - (checkedInductiveIntroVars intro) - <$> traverse directCondition - (checkedInductiveIntroConditions intro) - <*> pure - (checkedInductiveIntroResultTerm intro) - - directCondition = \case - CheckedInductiveSideCondition formula -> - Right - (TypedInductive.DirectSideCondition - formula) - CheckedInductiveRecursiveCondition - { checkedInductiveRecursiveTerm - , checkedInductiveRecursiveDirect = True - } -> - Right - (TypedInductive.DirectRecursiveCondition - checkedInductiveRecursiveTerm) - CheckedInductiveRecursiveCondition{} -> - Left - (checkingErrorAt context - "nested inductive recursion is not supported by the typed set-valued inductive slice") - -typedSourceGlobal - :: Transition.TransitionModuleBuilder - -> Symbol - -> Maybe - (TypedInductive.SourceGlobal - Transition.CheckedGlobalRef) -typedSourceGlobal builder symbol = do - reference <- - Transition.lookupTransitionGlobal - symbol - builder - pure - (TypedInductive.SourceGlobal - reference - (Transition.lookupTransitionGlobalBody - symbol - builder)) - -typedInductiveGuardImport - :: BlockContext - -> Transition.TransitionModuleBuilder - -> Int - -> Core.FrozenCheckedCore - Transition.CheckedGlobalRef - -> CheckingM Transition.TransitionDerivationImport -typedInductiveGuardImport - context - builder - ordinal - target = do - found <- - either - ( throwIO - . typedInductiveError - context - "typed inductive guard lookup failed: " - ) - pure - (Transition.lookupTransitionTypedImport - target - builder) - maybe - (throwIO - (checkingErrorAt context - ( "typed inductive domain guard " - <> Text.pack (show ordinal) - <> " has no authorized typed fact" - ))) - pure - found - -commitTypedInductiveFact - :: BlockContext - -> Vector Transition.TransitionDerivationImport - -> Transition.TransitionModuleBuilder - -> TypedInductive.PreparedTypedInductiveFact - Transition.CheckedGlobalRef - -> CheckingM Transition.TransitionModuleBuilder -commitTypedInductiveFact context imports builder fact = do - either - ( throwIO - . typedInductiveError - context - "typed inductive fact admission failed: " - ) - pure - (Transition.commitTransitionKernelFactWithImports - (TypedInductive.typedInductiveFactMarker - fact - :| []) - (typedFactOrigin context) - imports - (TypedInductive.typedInductiveFactTarget - fact) - (TypedInductive.typedInductiveFactDerivation - fact) - builder) - -commitTypedInductiveState - :: BlockContext - -> CheckedInductive - -> NonEmpty Marker - -> Transition.TransitionModuleBuilder - -> CheckingState - -> Either CheckingError CheckingState -commitTypedInductiveState - context - checked - factMarkers - builder - st = do - markers' <- - validatedMarkers - location - (marker : NonEmpty.toList factMarkers) - st - (owners', ownedMarkers', dependencies') <- - validatedSymbolRegistration - context - OwnedByInductiveDefinition - carrier - mempty - st - frozenSymbols <- - first - ( checkingErrorAt context - . ("inductive specification mentions unknown symbol " <>) - . symbolText - ) - (checkedInductiveFrozenSymbols - dependencies' - checked) - let frozen = - HM.fromList - [ (symbol, marker) - | symbol <- Set.toList frozenSymbols - , ownableSymbol symbol - ] - pure - st - { checkingDependencies = dependencies' - , checkingOwnedSymbols = owners' - , checkingOwnedSymbolMarkers = ownedMarkers' - , checkingFrozenSymbols = - HM.union - (checkingFrozenSymbols st) - frozen - , definedMarkers = markers' - , blockLabel = marker - , stepLocation = location - , checkingHypothesisCounter = 0 - , checkingTransitionModuleBuilder = - Just builder - } - where - location = - blockContextLocation context - marker = - blockContextMarker context - carrier = - SymbolMixfix - (checkedInductiveSymbol checked) - -typedInductiveError - :: Show error - => BlockContext - -> Text - -> error - -> CheckingError -typedInductiveError context prefix = - checkingErrorAt context - . (prefix <>) - . Text.pack - . show - -validateInductiveHeader - :: BlockContext - -> Symbol - -> CheckingState - -> Either CheckingError () -validateInductiveHeader context carrier st = do - void - (validatedMarkers - (blockContextLocation context) - [blockContextMarker context] - st) - void - (validatedSymbolRegistration - context - OwnedByInductiveDefinition - carrier - mempty - st) - --- | Validate and commit every state row introduced by one inductive. -commitInductive - :: BlockContext - -> CheckedInductive - -> NonEmpty Facts.StagedFact - -> CheckingState - -> Either CheckingError CheckingState -commitInductive context checked stagedFacts st = do - markers' <- - validatedMarkers - location - (marker : factMarkers) - st - (owners', ownedMarkers', dependencies') <- - validatedSymbolRegistration - context - OwnedByInductiveDefinition - carrier - mempty - st - frozenSymbols <- - first - ( checkingErrorAt context - . ("inductive specification mentions unknown symbol " <>) - . symbolText - ) - (checkedInductiveFrozenSymbols - dependencies' - checked) - traverse_ - (validatePreparedSemanticFact - context - owners' - dependencies') - (Facts.stagedFactSemantic <$> stagedFacts) - facts' <- - first - (DuplicateMarker location) - (Facts.registerStagedFacts - stagedFacts - (checkingFacts st)) - let frozen = - HM.fromList - [ (symbol, marker) - | symbol <- Set.toList frozenSymbols - , ownableSymbol symbol - ] - pure - st - { checkingFacts = facts' - , checkingDependencies = dependencies' - , checkingOwnedSymbols = owners' - , checkingOwnedSymbolMarkers = ownedMarkers' - , checkingFrozenSymbols = - HM.union - (checkingFrozenSymbols st) - frozen - , definedMarkers = markers' - , blockLabel = marker - , stepLocation = location - , checkingHypothesisCounter = 0 - } - where - location = - blockContextLocation context - marker = - blockContextMarker context - carrier = - SymbolMixfix (checkedInductiveSymbol checked) - factMarkers = - toList (stagedFacts >>= Facts.stagedFactAliases) - -normalizeInductive :: Inductive -> CheckingM CheckedInductive -normalizeInductive Inductive{..} = do - let duplicateParams = duplicateVars inductiveParams - unless (Set.null duplicateParams) do - throwCheckingError ("inductive parameters must be linear: " <> formatVars duplicateParams) - checkedInductiveDomain <- canonicalize inductiveDomain - let illegalDomainVars = freeVars checkedInductiveDomain `Set.difference` Set.fromList inductiveParams - unless (Set.null illegalDomainVars) do - throwCheckingError ("inductive domain may only mention the inductive parameters: " <> formatVars illegalDomainVars) - when (mentionsSymbol (SymbolMixfix inductiveSymbol) checkedInductiveDomain) do - throwCheckingError "inductive domain must be independent of the inductive symbol" - checkedInductiveIntros <- traverse (normalizeInductiveIntro inductiveSymbol inductiveParams) inductiveIntros - let checked = - CheckedInductive - { checkedInductiveSymbol = inductiveSymbol - , checkedInductiveParams = inductiveParams - , checkedInductiveDomain - , checkedInductiveIntros - } - ensureInductiveDefinitionIndependence checked - pure checked - -ensureInductiveDefinitionIndependence :: CheckedInductive -> Checking -ensureInductiveDefinitionIndependence checked = do - graph <- gets checkingDependencies - let carrier = SymbolMixfix (checkedInductiveSymbol checked) - externalSymbols = - Set.filter ownableSymbol - (Set.delete carrier (checkedInductiveMentionedSymbols checked)) - path <- - either - (\unknown -> - throwCheckingError - ("inductive specification mentions unknown symbol " <> symbolText unknown)) - pure - (Dependencies.dependencyPath graph externalSymbols carrier) - case path of - Nothing -> - skip - Just path -> - throwCheckingError - ( "inductive specification mentions symbol " - <> symbolText (NonEmpty.head path) - <> " whose definition depends on the inductive symbol " - <> functionSymbolText (checkedInductiveSymbol checked) - <> " via " - <> formatSymbolPath path - ) - -checkedInductiveFrozenSymbols - :: Dependencies.DependencyRegistry - -> CheckedInductive - -> Either Symbol (Set Symbol) -checkedInductiveFrozenSymbols graph checked = - let seeds = - Set.filter ownableSymbol - (checkedInductiveMentionedSymbols checked) - in Dependencies.dependencyClosure graph seeds - -normalizeInductiveIntro :: FunctionSymbol -> [VarSymbol] -> IntroRule -> CheckingM CheckedInductiveIntro -normalizeInductiveIntro symbol params IntroRule{introConditions, introResult} = do - introConditions' <- traverse canonicalize introConditions - introResult' <- canonicalize introResult - checkedInductiveIntroConditions <- traverse (normalizeInductiveCondition symbol params) introConditions' - checkedInductiveIntroResultTerm <- normalizeInductiveResult symbol params introResult' - let paramSet = Set.fromList params - checkedInductiveIntroVars = - List.filter (`Set.notMember` paramSet) (orderedUniqueVars (concatMap toList introConditions' <> toList checkedInductiveIntroResultTerm)) - pure CheckedInductiveIntro - { checkedInductiveIntroVars - , checkedInductiveIntroConditions - , checkedInductiveIntroResultTerm - } - -normalizeInductiveResult :: FunctionSymbol -> [VarSymbol] -> Formula -> CheckingM Term -normalizeInductiveResult symbol params = \case - IsElementOf _ resultTerm carrier - | not (matchesInductiveCarrier symbol (TermVar <$> params) carrier) -> - throwCheckingError "inductive rule result must have the form t \\in F(args)" - | mentionsSymbol (SymbolMixfix symbol) resultTerm -> - throwCheckingError "inductive rule result term must not mention the inductive symbol" - | otherwise -> - pure resultTerm - _ -> - throwCheckingError "inductive rule result must have the form t \\in F(args)" - -normalizeInductiveCondition :: FunctionSymbol -> [VarSymbol] -> Formula -> CheckingM CheckedInductiveCondition -normalizeInductiveCondition symbol params phi - | not (mentionsSymbol (SymbolMixfix symbol) phi) = - pure (CheckedInductiveSideCondition phi) - | otherwise = case phi of - IsElementOf _ recursiveTerm recursiveCarrier -> do - when (mentionsSymbol (SymbolMixfix symbol) recursiveTerm) do - throwCheckingError "inductive recursive occurrence must appear in the carrier of a membership premise" - let placeholder = - freshGeneratedVar - (freeVars phi <> Set.fromList params) - "__inductive" - -- Ordinary definitions are tracked separately through the top-level - -- freshness/dependency checks. At this stage we only decompose the - -- explicit recursive carrier occurrence that remains in the premise. - recursiveCarrierTemplateExpr <- - either throwCheckingError pure - (replaceInductiveApplications symbol (TermVar <$> params) (TermVar placeholder) recursiveCarrier) - let checkedInductiveRecursiveDirect = recursiveCarrierTemplateExpr == TermVar placeholder - pure CheckedInductiveRecursiveCondition - { checkedInductiveRecursiveTerm = recursiveTerm - , checkedInductiveRecursiveCarrierTemplate = abstractVarSymbol placeholder recursiveCarrierTemplateExpr - , checkedInductiveRecursiveDirect - } - _ -> - throwCheckingError "inductive recursive premise must be a direct membership condition" - -replaceInductiveApplications :: Eq a => FunctionSymbol -> [ExprOf a] -> ExprOf a -> ExprOf a -> Either Text (ExprOf a) -replaceInductiveApplications symbol targetArgs replacement = - go targetArgs replacement - where - go :: Eq a => [ExprOf a] -> ExprOf a -> ExprOf a -> Either Text (ExprOf a) - go liftedArgs liftedReplacement = \case - TermVar x -> - Right (TermVar x) - TermSymbol loc sym args - | sym == SymbolMixfix symbol && sameInductiveArgs liftedArgs args -> - Right liftedReplacement - | sym == SymbolMixfix symbol -> - Left ("inductive symbol " <> functionSymbolText symbol <> " occurred with the wrong arguments") - | otherwise -> - TermSymbol loc sym <$> traverse (go liftedArgs liftedReplacement) args - TermSymbolStruct structSymbol expr -> - TermSymbolStruct structSymbol <$> traverse (go liftedArgs liftedReplacement) expr - Apply expr args -> - Apply <$> go liftedArgs liftedReplacement expr <*> traverse (go liftedArgs liftedReplacement) args - TermSep x bound scope -> do - bound' <- go liftedArgs liftedReplacement bound - scope' <- go (map (F <$>) liftedArgs) (F <$> liftedReplacement) (fromScope scope) - pure (TermSep x bound' (toScope scope')) - ReplacePred y x bound scope -> do - bound' <- go liftedArgs liftedReplacement bound - scope' <- go (map (F <$>) liftedArgs) (F <$> liftedReplacement) (fromScope scope) - pure (ReplacePred y x bound' (toScope scope')) - ReplaceFun bounds lhs cond -> do - bounds' <- traverse (\(x, bound) -> do - bound' <- go liftedArgs liftedReplacement bound - pure (x, bound')) bounds - lhs' <- go (map (F <$>) liftedArgs) (F <$> liftedReplacement) (fromScope lhs) - cond' <- go (map (F <$>) liftedArgs) (F <$> liftedReplacement) (fromScope cond) - pure (ReplaceFun bounds' (toScope lhs') (toScope cond')) - Connected conn left right -> - Connected conn <$> go liftedArgs liftedReplacement left <*> go liftedArgs liftedReplacement right - Lambda scope -> do - scope' <- go (map (F <$>) liftedArgs) (F <$> liftedReplacement) (fromScope scope) - pure (Lambda (toScope scope')) - Quantified quant scope -> do - scope' <- go (map (F <$>) liftedArgs) (F <$> liftedReplacement) (fromScope scope) - pure (Quantified quant (toScope scope')) - PropositionalConstant p -> - Right (PropositionalConstant p) - Not loc expr -> - Not loc <$> go liftedArgs liftedReplacement expr - -matchesInductiveCarrier :: Eq a => FunctionSymbol -> [ExprOf a] -> ExprOf a -> Bool -matchesInductiveCarrier symbol targetArgs = \case - TermSymbol _loc (SymbolMixfix symbol') args -> - symbol == symbol' && sameInductiveArgs targetArgs args - _ -> - False - -sameInductiveArgs :: Eq a => [ExprOf a] -> [ExprOf a] -> Bool -sameInductiveArgs left right = - length left == length right && and (zipWith equivalent left right) - -orderedUniqueVars :: Ord a => [a] -> [a] -orderedUniqueVars = - reverse . snd . foldl' step (Set.empty, []) - where - step (seen, acc) x - | x `Set.member` seen = (seen, acc) - | otherwise = (Set.insert x seen, x : acc) - -inductiveCarrierTerm :: CheckedInductive -> Expr -inductiveCarrierTerm CheckedInductive{checkedInductiveSymbol, checkedInductiveParams} = - TermOp Nowhere checkedInductiveSymbol (TermVar <$> checkedInductiveParams) - -inductiveConditionFormula :: CheckedInductive -> CheckedInductiveCondition -> Formula -inductiveConditionFormula checked = - inductiveConditionFormulaAt checked (inductiveCarrierTerm checked) - -inductiveConditionFormulaAt :: CheckedInductive -> Expr -> CheckedInductiveCondition -> Formula -inductiveConditionFormulaAt _ replacement = \case - CheckedInductiveSideCondition phi -> - phi - CheckedInductiveRecursiveCondition{checkedInductiveRecursiveTerm, checkedInductiveRecursiveCarrierTemplate} -> - isElementOf checkedInductiveRecursiveTerm (instantiate1 replacement checkedInductiveRecursiveCarrierTemplate) - -semanticSubsetFormula :: Set VarSymbol -> Expr -> Expr -> Formula -semanticSubsetFormula reserved left right = - makeForall [witnessVar] - (isElementOf (TermVar witnessVar) left `Implies` isElementOf (TermVar witnessVar) right) - where - witnessVar = freshGeneratedVar (reserved <> freeVars left <> freeVars right) "x" - -inductiveSoundnessGoals :: CheckedInductive -> [Formula] -inductiveSoundnessGoals checked = - inductiveMonotonicityGoals checked <> inductiveDomainGoals checked - -inductiveMonotonicityGoals :: CheckedInductive -> [Formula] -inductiveMonotonicityGoals checked = - [ forallIfNeeded [leftVar, rightVar] - ( semanticSubsetFormula usedVars (TermVar leftVar) (TermVar rightVar) - `Implies` - semanticSubsetFormula usedVars - (instantiate1 (TermVar leftVar) checkedInductiveRecursiveCarrierTemplate) - (instantiate1 (TermVar rightVar) checkedInductiveRecursiveCarrierTemplate) - ) - | intro <- NonEmpty.toList (checkedInductiveIntros checked) - , CheckedInductiveRecursiveCondition{checkedInductiveRecursiveCarrierTemplate, checkedInductiveRecursiveDirect} <- checkedInductiveIntroConditions intro - , not checkedInductiveRecursiveDirect - ] - where - usedVars = inductiveUsedVars checked - leftVar = freshGeneratedVar usedVars "xa" - rightVar = freshGeneratedVar (Set.insert leftVar usedVars) "xb" - -inductiveDomainGoals :: CheckedInductive -> [Formula] -inductiveDomainGoals checked = - [ forallIfNeeded (orderedUniqueVars (checkedInductiveParams checked <> checkedInductiveIntroVars intro)) - (impliesFrom premises conclusion) - | intro <- NonEmpty.toList (checkedInductiveIntros checked) - , let premises = inductiveConditionFormulaAt checked (checkedInductiveDomain checked) <$> checkedInductiveIntroConditions intro - conclusion = isElementOf (checkedInductiveIntroResultTerm intro) (checkedInductiveDomain checked) - ] - -inductiveFacts - :: Marker - -> CheckedInductive - -> NonEmpty (Marker, Formula) -inductiveFacts marker checked = - inductiveIntroFacts marker checked - <> ( ( inductiveDomSubsetMarker marker - , inductiveDomSubsetFormula checked - ) - :| [ ( inductiveCasesMarker marker - , inductiveCasesFormula checked - ) - , ( inductiveInductMarker marker - , inductiveInductFormula checked - ) - ] - ) - -inductiveFactRoles - :: CheckedInductive - -> [LegacyInductiveFactRole] -inductiveFactRoles checked = - replicate - (length (checkedInductiveIntros checked)) - LegacyInductiveIntroduction - <> [ LegacyInductiveDomainSubset - , LegacyInductiveCases - , LegacyInductiveInduction - ] - -inductiveIntroFacts - :: Marker - -> CheckedInductive - -> NonEmpty (Marker, Formula) -inductiveIntroFacts marker checked = - NonEmpty.zipWith - (\index intro -> - ( inductiveIntroMarker marker index - , inductiveIntroFormula checked intro - )) - (1 :| [2 ..]) - (checkedInductiveIntros checked) - -inductiveIntroMarker :: Marker -> Int -> Marker -inductiveIntroMarker marker index = - Marker (inductiveMarkerText marker <> "_intro_" <> Text.pack (show index)) - -inductiveDomSubsetMarker :: Marker -> Marker -inductiveDomSubsetMarker marker = - Marker (inductiveMarkerText marker <> "_dom_subset") - -inductiveCasesMarker :: Marker -> Marker -inductiveCasesMarker marker = - Marker (inductiveMarkerText marker <> "_cases") - -inductiveInductMarker :: Marker -> Marker -inductiveInductMarker marker = - Marker (inductiveMarkerText marker <> "_induct") - -inductiveMarkerText :: Marker -> Text -inductiveMarkerText (Marker text) = text - -inductiveIntroFormula :: CheckedInductive -> CheckedInductiveIntro -> Formula -inductiveIntroFormula checked intro = - forallIfNeeded - (orderedUniqueVars (checkedInductiveParams checked <> checkedInductiveIntroVars intro)) - (impliesFrom premises conclusion) - where - premises = inductiveConditionFormula checked <$> checkedInductiveIntroConditions intro - conclusion = isElementOf (checkedInductiveIntroResultTerm intro) (inductiveCarrierTerm checked) - -inductiveDomSubsetFormula :: CheckedInductive -> Formula -inductiveDomSubsetFormula checked = - forallIfNeeded (checkedInductiveParams checked) - (semanticSubsetFormula (inductiveUsedVars checked) (inductiveCarrierTerm checked) (checkedInductiveDomain checked)) - -inductiveCasesFormula :: CheckedInductive -> Formula -inductiveCasesFormula checked = - forallIfNeeded - (orderedUniqueVars (checkedInductiveParams checked <> [witnessVar])) - (impliesFrom [isElementOf (TermVar witnessVar) (inductiveCarrierTerm checked)] (makeDisjunction disjuncts)) - where - witnessVar = freshGeneratedVar (inductiveUsedVars checked) "x" - disjuncts = inductiveCaseDisjunct witnessVar <$> NonEmpty.toList (checkedInductiveIntros checked) - inductiveCaseDisjunct x intro = - existsIfNeeded - (checkedInductiveIntroVars intro) - (makeConjunction (premises <> [Equals Nowhere (TermVar x) (checkedInductiveIntroResultTerm intro)])) - where - premises = inductiveConditionFormula checked <$> checkedInductiveIntroConditions intro - -inductiveInductFormula :: CheckedInductive -> Formula -inductiveInductFormula checked = - forallIfNeeded - (orderedUniqueVars (checkedInductiveParams checked <> [subsetVar])) - (impliesFrom closures conclusion) - where - subsetVar = freshGeneratedVar (inductiveUsedVars checked) "S" - closures = inductiveInductionClosure checked subsetVar <$> NonEmpty.toList (checkedInductiveIntros checked) - conclusion = - semanticSubsetFormula - (Set.insert subsetVar (inductiveUsedVars checked)) - (inductiveCarrierTerm checked) - (TermVar subsetVar) - -inductiveInductionClosure :: CheckedInductive -> VarSymbol -> CheckedInductiveIntro -> Formula -inductiveInductionClosure checked subsetVar intro = - forallIfNeeded (checkedInductiveIntroVars intro) (impliesFrom premises conclusion) - where - premises = inductiveConditionFormulaAt checked (TermVar subsetVar) <$> checkedInductiveIntroConditions intro - conclusion = isElementOf (checkedInductiveIntroResultTerm intro) (TermVar subsetVar) - -inductiveUsedVars :: CheckedInductive -> Set VarSymbol -inductiveUsedVars CheckedInductive{checkedInductiveParams, checkedInductiveIntros} = - Set.fromList - ( checkedInductiveParams - <> [ var - | intro <- NonEmpty.toList checkedInductiveIntros - , var <- checkedInductiveIntroVars intro - ] - ) - -checkStructDefn :: BlockContext -> StructDefn -> Checking -checkStructDefn context structDefn@StructDefn{..} = do - structGraph <- gets checkingStructs - resolvedParents <- - forM (Set.toList structParents) \parent -> - case StructGraph.lookup parent structGraph of - Nothing -> - throwIO - (UnknownStructureParent - parent - (blockContextLocation context) - (blockContextMarker context)) - Just struct -> - pure struct - let ancestors = - structParents - <> Set.unions (StructGraph.structAncestors <$> resolvedParents) - inheritedSymbols = - Set.unions (StructGraph.structSymbols <$> resolvedParents) - structContext = - structContextFromSymbols - structDefnLabel - (structDefnFixes <> inheritedSymbols) - assumptions <- - forM structDefnAssumes \(assumptionMarker, assumption) -> do - canonical <- - canonicalizeWithAt context structContext assumption - pure (assumptionMarker, canonical) - let canonicalStructDefn = - structDefn{structDefnAssumes = assumptions} - checked <- - either - (throwIO . structurePreparationCheckingError context) - pure - (Structure.prepareCheckedStructDefn - (blockContextLocation context) - (blockContextMarker context) - canonicalStructDefn - ancestors - inheritedSymbols) - st <- get - committed <- - either - throwIO - pure - (commitCheckedStructDefn context checked st) - putDeclarationCandidate committed - setDeclarationFactProducers - ( LegacyDeclarationRuleProducer - . LegacyStructureRule - <$> NonEmpty.toList - (Structure.checkedStructFactRoles checked) - ) - -structurePreparationCheckingError - :: BlockContext - -> Structure.StructurePreparationError - -> CheckingError -structurePreparationCheckingError context = \case - Structure.SelfReferentialStructure symbol -> - CheckingError - ( "structure definition of symbol " - <> symbolText symbol - <> " is self-referential" - ) - (blockContextLocation context) - (blockContextMarker context) - --- | Validate and commit every state row introduced by one structure. -commitCheckedStructDefn - :: BlockContext - -> Structure.CheckedStructDefn - -> CheckingState - -> Either CheckingError CheckingState -commitCheckedStructDefn context checked st = do - markers' <- - validatedMarkers - location - (NonEmpty.toList (Structure.checkedStructMarkers checked)) - st - (owners', ownedMarkers') <- - first (checkingErrorAt context) - (validatedOwnership - marker - OwnedByStructureDefinition - structureSymbol - st) - dependencies' <- - first - (checkingErrorAt context . dependencyRegistrationErrorText structureSymbol) - (Dependencies.registerDependencies - structureSymbol - semanticDependencies - (checkingDependencies st)) - traverse_ - (validatePreparedDependencies dependencies') - (Structure.checkedStructSemanticFacts checked) - facts' <- - first - (DuplicateMarker location) - (Facts.registerStagedFacts - (Structure.checkedStructFacts checked) - (checkingFacts st)) - pure - st - { checkingFacts = facts' - , checkingDependencies = dependencies' - , checkingOwnedSymbols = owners' - , checkingOwnedSymbolMarkers = ownedMarkers' - , checkingStructs = - StructGraph.insert - (Structure.checkedStructPhrase checked) - (Structure.checkedStructAncestors checked) - (Structure.checkedStructInternalSymbols checked) - (Structure.checkedStructAllSymbols checked) - (checkingStructs st) - , definedMarkers = markers' - , blockLabel = marker - , stepLocation = location - , checkingHypothesisCounter = 0 - } - where - location = blockContextLocation context - marker = blockContextMarker context - structureSymbol = Structure.checkedStructSymbol checked - semanticDependencies = - Set.filter ownableSymbol - (Structure.checkedStructDependencies checked) - - validatePreparedDependencies dependencyRegistry prepared = - case - Set.lookupMin - ( Set.filter - (\dependency -> - ownableSymbol dependency - && isNothing - (Dependencies.lookupDependencies - dependency - dependencyRegistry)) - (Facts.preparedSemanticDependencies prepared) - ) - of - Nothing -> - Right () - Just unknown -> - Left - (checkingErrorAt context - ( "structure fact depends on unknown symbol " - <> symbolText unknown - )) - -checkingErrorAt :: BlockContext -> Text -> CheckingError -checkingErrorAt context message = - CheckingError - message - (blockContextLocation context) - (blockContextMarker context) - - -fixing :: NonEmpty VarSymbol -> Checking -fixing xs = do - goals <- gets checkingGoals - (goal, goals') <- case goals of - goal : goals' -> return (goal, goals') - _ -> throwWithLocationAndMarker (CheckingError "No open goals, cannot use \"fix\" step") - goal' <- case goal of - Forall body | [_bv] <- nubOrd (bindings body) -> - -- If there's only one quantified variable we can freely choose a new name. - -- This is useful for nameless quantified phrases such as @every _ is an element of _@. - case xs of - x :| [] -> return (instantiate (\_bv -> TermVar x) body) - _ -> throwWithLocationAndMarker (CheckingError "Couldn't use \"fix\" step: only one bound variable but multiple variables to be fixed") - Forall body | toList xs `List.intersect` nubOrd (bindings body) == toList xs -> - return (Forall (instantiateSome xs body)) - Forall body -> - throwWithLocationAndMarker (CheckingError ("You can only use a \"fix\" step if all specified variables occur in the outermost quantifier. Variables to be fixed were: " - <> Text.pack (show xs) <> " but only the following are bound: " <> Text.pack (show (nubOrd (bindings body))))) - _ -> - throwWithLocationAndMarker (CheckingError "You can only use a \"fix\" step if the goal is universal.") - setGoals (goal' : goals') - --- | A trusted rule that reduces a goal after introducing one assumption. -data GoalReduction - = ImplicationIntroduction Formula Formula - | CurryLeftConjunct Formula Formula Formula - | CurryRightConjunct Formula Formula Formula - deriving (Show, Eq) - -goalReductionAssumption :: GoalReduction -> Formula -goalReductionAssumption = \case - ImplicationIntroduction assumption _conclusion -> - assumption - CurryLeftConjunct assumption _right _conclusion -> - assumption - CurryRightConjunct _left assumption _conclusion -> - assumption - -goalReductionResidual :: GoalReduction -> Formula -goalReductionResidual = \case - ImplicationIntroduction _assumption conclusion -> - conclusion - CurryLeftConjunct _assumption right conclusion -> - right `Implies` conclusion - CurryRightConjunct left _assumption conclusion -> - left `Implies` conclusion - -reduceGoalWithAssumption :: Formula -> Formula -> Maybe GoalReduction -reduceGoalWithAssumption assumption = \case - (left `And` right) `Implies` conclusion - | equivalent left assumption -> - Just (CurryLeftConjunct assumption right conclusion) - | equivalent right assumption -> - Just (CurryRightConjunct left assumption conclusion) - antecedent `Implies` conclusion - | equivalent antecedent assumption -> - Just (ImplicationIntroduction assumption conclusion) - _ -> - Nothing - --- | An assumption step in a proof is supposed to match the goal. -matchAssumptionWithGoal :: Location -> Formula -> CheckingM [Formula] -matchAssumptionWithGoal loc asm = do - asm' <- canonicalize asm - goals <- gets checkingGoals - (goal, goals') <- case goals of - goal : goals' -> - pure (goal, goals') - [] -> - impossible "assumption proof step without an open goal" - defns <- gets checkingPredicateDefinitions - case reduceGoalWithAssumption asm' goal of - Just reduction -> - pure (goalReductionResidual reduction : goals') - -- - -- Unfolding definitions against atomic goals - Nothing -> case goal of - phi@(Atomic _pos p args) -> - let rhos = (HM.lookup p defns ?? []) - rhos' = - [ instantiate - (\k -> - nth k args - ?? impossible - "predicate definition index exceeds application arity") - (absurd <$> rho) - | rho <- rhos - ] - in case firstJust (reduceGoalWithAssumption asm') rhos' of - Nothing -> throwWithMarker (MismatchedAssume asm' phi loc) - Just reduction -> - pure (goalReductionResidual reduction : goals') - phi -> throwWithMarker (MismatchedAssume asm' phi loc) - - -checkAbbr :: BlockContext -> Abbreviation -> Checking -checkAbbr context (Abbreviation symbol scope) = do - scope' <- transverseScope unabbreviate scope - when (mentionsSymbol symbol (fromScope scope')) do - throwIO - (checkingErrorAt - context - "abbreviation is self-referential") - st <- get - either - throwIO - put - (commitAbbreviation context symbol scope' st) - --- | Validate and commit every state row introduced by one abbreviation. -commitAbbreviation - :: BlockContext - -> Symbol - -> Scope Int ExprOf Void - -> CheckingState - -> Either CheckingError CheckingState -commitAbbreviation context symbol scope st = do - markers' <- - validatedMarkers location [marker] st - (owners', ownedMarkers', dependencies') <- - validatedSymbolRegistration - context - OwnedByAbbreviation - symbol - mempty - st - pure - st - { checkingAbbreviations = - HM.insert - symbol - scope - (checkingAbbreviations st) - , checkingDependencies = dependencies' - , checkingOwnedSymbols = owners' - , checkingOwnedSymbolMarkers = ownedMarkers' - , definedMarkers = markers' - , blockLabel = marker - , stepLocation = location - , checkingHypothesisCounter = 0 - } - where - location = - blockContextLocation context - marker = - blockContextMarker context |
