module Agda.Syntax.Concrete.Definitions.Errors where import Control.DeepSeq import GHC.Generics (Generic) import Agda.Syntax.Position import Agda.Syntax.Common import Agda.Syntax.Common.Pretty import Agda.Syntax.Concrete import Agda.Syntax.Concrete.Definitions.Types import Agda.Interaction.Options.Warnings import Agda.Utils.Null ( empty ) import Agda.Utils.CallStack ( CallStack ) import Agda.Utils.List1 (List1, pattern (:|)) import Agda.Utils.List2 (List2, pattern List2) import qualified Agda.Utils.List1 as List1 import Agda.Utils.Singleton ------------------------------------------------------------------------ -- Errors -- | Exception with internal source code callstack data DeclarationException = DeclarationException { deLocation :: CallStack , deException :: DeclarationException' } -- | The exception type. data DeclarationException' = MultipleEllipses Pattern | InvalidName Name | DuplicateDefinition Name | DuplicateAnonDeclaration Range | MissingWithClauses Name LHS | WrongDefinition Name DataRecOrFun DataRecOrFun | DeclarationPanic String | WrongContentBlock KindOfBlock Range | AmbiguousFunClauses LHS (List1 Name) -- ^ In a mutual block, a clause could belong to any of the ≥2 type signatures ('Name'). | AmbiguousConstructor Range Name [Name] -- ^ In an interleaved mutual block, a constructor could belong to any of the data signatures ('Name') | InvalidMeasureMutual Range -- ^ In a mutual block, all or none need a MEASURE pragma. -- Range is of mutual block. | UnquoteDefRequiresSignature (List1 Name) | BadMacroDef NiceDeclaration | UnfoldingOutsideOpaque Range -- ^ An unfolding declaration was not the first declaration -- contained in an opaque block. | OpaqueInMutual Range -- ^ @opaque@ block nested in a @mutual@ block. This can never -- happen, even with reordering. | DisallowedInterleavedMutual Range String (List1 Name) -- ^ A declaration that breaks an implicit mutual block (named by -- the String argument) was present while the given lone type -- signatures were still without their definitions. deriving Show ------------------------------------------------------------------------ -- Warnings data DeclarationWarning = DeclarationWarning { dwLocation :: CallStack , dwWarning :: DeclarationWarning' } deriving (Show, Generic) -- | Non-fatal errors encountered in the Nicifier. data DeclarationWarning' -- Please keep in alphabetical order. = EmptyAbstract Range -- ^ Empty @abstract@ block. | EmptyConstructor Range -- ^ Empty @constructor@ block. | EmptyField Range -- ^ Empty @field@ block. | EmptyGeneralize Range -- ^ Empty @variable@ block. | EmptyInstance Range -- ^ Empty @instance@ block | EmptyMacro Range -- ^ Empty @macro@ block. | EmptyMutual Range -- ^ Empty @mutual@ block. | EmptyPostulate Range -- ^ Empty @postulate@ block. | EmptyPrivate Range -- ^ Empty @private@ block. | EmptyPrimitive Range -- ^ Empty @primitive@ block. | HiddenGeneralize Range -- ^ A 'Hidden' identifier in a @variable@ declaration. -- Hiding has no effect there as generalized variables are always hidden -- (or instance variables). | InvalidCatchallPragma Range -- ^ A {-\# CATCHALL \#-} pragma -- that does not precede a function clause. | InvalidConstructor Range -- ^ Invalid definition in a constructor block | InvalidConstructorBlock Range -- ^ Invalid constructor block (not inside an interleaved mutual block) | InvalidCoverageCheckPragma Range -- ^ A {-\# NON_COVERING \#-} pragma that does not apply to any function. | InvalidNoPositivityCheckPragma Range -- ^ A {-\# NO_POSITIVITY_CHECK \#-} pragma -- that does not apply to any data or record type. | InvalidNoUniverseCheckPragma Range -- ^ A {-\# NO_UNIVERSE_CHECK \#-} pragma -- that does not apply to a data or record type. | InvalidRecordDirective Range -- ^ A record directive outside of a record / below existing fields. | InvalidTerminationCheckPragma Range -- ^ A {-\# TERMINATING \#-} and {-\# NON_TERMINATING \#-} pragma -- that does not apply to any function. | MissingDeclarations [(Name, Range)] -- ^ Definitions (e.g. constructors or functions) without a declaration. | MissingDefinitions [(Name, Range)] -- ^ Declarations (e.g. type signatures) without a definition. | NotAllowedInMutual Range String | OpenPublicPrivate Range -- ^ @private@ has no effect on @open public@. (But the user might think so.) | OpenPublicAbstract Range -- ^ @abstract@ has no effect on @open public@. (But the user might think so.) | PolarityPragmasButNotPostulates [Name] | PragmaNoTerminationCheck Range -- ^ Pragma @{-\# NO_TERMINATION_CHECK \#-}@ has been replaced -- by @{-\# TERMINATING \#-}@ and @{-\# NON_TERMINATING \#-}@. | PragmaCompiled Range -- ^ @COMPILE@ pragmas are not allowed in safe mode. | SafeFlagEta Range -- ^ @ETA@ pragma is unsafe. | SafeFlagInjective Range -- ^ @INJECTIVE@ pragma is unsafe. | SafeFlagNoCoverageCheck Range -- ^ @NON_COVERING@ pragma is unsafe. | SafeFlagNoPositivityCheck Range -- ^ @NO_POSITIVITY_CHECK@ pragma is unsafe. | SafeFlagNoUniverseCheck Range -- ^ @NO_UNIVERSE_CHECK@ pragma is unsafe. | SafeFlagNonTerminating Range -- ^ @NON_TERMINATING@ pragma is unsafe. | SafeFlagPolarity Range -- ^ @POLARITY@ pragma is unsafe. | SafeFlagTerminating Range -- ^ @TERMINATING@ pragma is unsafe. | ShadowingInTelescope (List1 (Name, List2 Range)) | UnknownFixityInMixfixDecl [Name] | UnknownNamesInFixityDecl [Name] | UnknownNamesInPolarityPragmas [Name] | UselessAbstract Range -- ^ @abstract@ block with nothing that can (newly) be made abstract. | UselessInstance Range -- ^ @instance@ block with nothing that can (newly) become an instance. | UselessPrivate Range -- ^ @private@ block with nothing that can (newly) be made private. deriving (Show, Generic) declarationWarningName :: DeclarationWarning -> WarningName declarationWarningName = declarationWarningName' . dwWarning declarationWarningName' :: DeclarationWarning' -> WarningName declarationWarningName' = \case -- Please keep in alphabetical order. EmptyAbstract{} -> EmptyAbstract_ EmptyConstructor{} -> EmptyConstructor_ EmptyField{} -> EmptyField_ EmptyGeneralize{} -> EmptyGeneralize_ EmptyInstance{} -> EmptyInstance_ EmptyMacro{} -> EmptyMacro_ EmptyMutual{} -> EmptyMutual_ EmptyPrivate{} -> EmptyPrivate_ EmptyPostulate{} -> EmptyPostulate_ EmptyPrimitive{} -> EmptyPrimitive_ HiddenGeneralize{} -> HiddenGeneralize_ InvalidCatchallPragma{} -> InvalidCatchallPragma_ InvalidConstructor{} -> InvalidConstructor_ InvalidConstructorBlock{} -> InvalidConstructorBlock_ InvalidNoPositivityCheckPragma{} -> InvalidNoPositivityCheckPragma_ InvalidNoUniverseCheckPragma{} -> InvalidNoUniverseCheckPragma_ InvalidRecordDirective{} -> InvalidRecordDirective_ InvalidTerminationCheckPragma{} -> InvalidTerminationCheckPragma_ InvalidCoverageCheckPragma{} -> InvalidCoverageCheckPragma_ MissingDeclarations{} -> MissingDeclarations_ MissingDefinitions{} -> MissingDefinitions_ NotAllowedInMutual{} -> NotAllowedInMutual_ OpenPublicPrivate{} -> OpenPublicPrivate_ OpenPublicAbstract{} -> OpenPublicAbstract_ PolarityPragmasButNotPostulates{} -> PolarityPragmasButNotPostulates_ PragmaNoTerminationCheck{} -> PragmaNoTerminationCheck_ PragmaCompiled{} -> PragmaCompiled_ SafeFlagEta {} -> SafeFlagEta_ SafeFlagInjective {} -> SafeFlagInjective_ SafeFlagNoCoverageCheck {} -> SafeFlagNoCoverageCheck_ SafeFlagNoPositivityCheck {} -> SafeFlagNoPositivityCheck_ SafeFlagNoUniverseCheck {} -> SafeFlagNoUniverseCheck_ SafeFlagNonTerminating {} -> SafeFlagNonTerminating_ SafeFlagPolarity {} -> SafeFlagPolarity_ SafeFlagTerminating {} -> SafeFlagTerminating_ ShadowingInTelescope{} -> ShadowingInTelescope_ UnknownFixityInMixfixDecl{} -> UnknownFixityInMixfixDecl_ UnknownNamesInFixityDecl{} -> UnknownNamesInFixityDecl_ UnknownNamesInPolarityPragmas{} -> UnknownNamesInPolarityPragmas_ UselessAbstract{} -> UselessAbstract_ UselessInstance{} -> UselessInstance_ UselessPrivate{} -> UselessPrivate_ -- | Nicifier warnings turned into errors in @--safe@ mode. unsafeDeclarationWarning :: DeclarationWarning -> Bool unsafeDeclarationWarning = unsafeDeclarationWarning' . dwWarning unsafeDeclarationWarning' :: DeclarationWarning' -> Bool unsafeDeclarationWarning' = \case -- Please keep in alphabetical order. EmptyAbstract{} -> False EmptyConstructor{} -> False EmptyField{} -> False EmptyGeneralize{} -> False EmptyInstance{} -> False EmptyMacro{} -> False EmptyMutual{} -> False EmptyPrivate{} -> False EmptyPostulate{} -> False EmptyPrimitive{} -> False HiddenGeneralize{} -> False InvalidCatchallPragma{} -> False InvalidConstructor{} -> False InvalidConstructorBlock{} -> False InvalidNoPositivityCheckPragma{} -> False InvalidNoUniverseCheckPragma{} -> False InvalidRecordDirective{} -> False InvalidTerminationCheckPragma{} -> False InvalidCoverageCheckPragma{} -> False MissingDeclarations{} -> True -- not safe MissingDefinitions{} -> True -- not safe NotAllowedInMutual{} -> False -- really safe? OpenPublicPrivate{} -> False OpenPublicAbstract{} -> False PolarityPragmasButNotPostulates{} -> False PragmaNoTerminationCheck{} -> True -- not safe PragmaCompiled{} -> True -- not safe SafeFlagEta {} -> True SafeFlagInjective {} -> True SafeFlagNoCoverageCheck {} -> True SafeFlagNoPositivityCheck {} -> True SafeFlagNoUniverseCheck {} -> True SafeFlagNonTerminating {} -> True SafeFlagPolarity {} -> True SafeFlagTerminating {} -> True ShadowingInTelescope{} -> False UnknownFixityInMixfixDecl{} -> False UnknownNamesInFixityDecl{} -> False UnknownNamesInPolarityPragmas{} -> False UselessAbstract{} -> False UselessInstance{} -> False UselessPrivate{} -> False -- | Pragmas not allowed in @--safe@ mode produce an 'unsafeDeclarationWarning'. -- unsafePragma :: CMaybe DeclarationWarning' m => Pragma -> m unsafePragma p = case p of BuiltinPragma{} -> empty CatchallPragma{} -> empty CompilePragma{} -> singleton $ PragmaCompiled r DisplayPragma{} -> empty EtaPragma{} -> singleton $ SafeFlagEta r ForeignPragma{} -> empty ImpossiblePragma{} -> empty InjectivePragma{} -> singleton $ SafeFlagInjective r InlinePragma{} -> empty NoCoverageCheckPragma{} -> singleton $ SafeFlagNoCoverageCheck r NoPositivityCheckPragma{} -> singleton $ SafeFlagNoPositivityCheck r NoUniverseCheckPragma{} -> singleton $ SafeFlagNoUniverseCheck r NotProjectionLikePragma{} -> empty OptionsPragma{} -> empty PolarityPragma{} -> singleton $ SafeFlagPolarity r RewritePragma{} -> empty -- @RewritePragma@ already requires --rewriting which is incompatible with --safe StaticPragma{} -> empty TerminationCheckPragma _ m -> case m of NonTerminating -> singleton $ SafeFlagNonTerminating r Terminating -> singleton $ SafeFlagTerminating r TerminationCheck -> empty TerminationMeasure{} -> empty -- @NO_TERMINATION_CHECK@ pragma was removed, but still parses. See Issue #1763. -- There is the unsafe @'PragmaNoTerminationCheck'@ warning thrown already, -- so we need not throw anything here. NoTerminationCheck -> empty WarningOnImport{} -> empty WarningOnUsage{} -> empty where r = getRange p ------------------------------------------------------------------------ -- Instances instance HasRange DeclarationException where getRange (DeclarationException _ err) = getRange err instance HasRange DeclarationException' where getRange (MultipleEllipses d) = getRange d getRange (InvalidName x) = getRange x getRange (DuplicateDefinition x) = getRange x getRange (DuplicateAnonDeclaration r) = r getRange (MissingWithClauses x lhs) = getRange lhs getRange (WrongDefinition x k k') = getRange x getRange (AmbiguousFunClauses lhs xs) = getRange lhs getRange (AmbiguousConstructor r _ _) = r getRange (DeclarationPanic _) = noRange getRange (WrongContentBlock _ r) = r getRange (InvalidMeasureMutual r) = r getRange (UnquoteDefRequiresSignature x) = getRange x getRange (BadMacroDef d) = getRange d getRange (UnfoldingOutsideOpaque r) = r getRange (OpaqueInMutual r) = r getRange (DisallowedInterleavedMutual r _ _) = r instance HasRange DeclarationWarning where getRange (DeclarationWarning _ w) = getRange w instance HasRange DeclarationWarning' where getRange = \case EmptyAbstract r -> r EmptyConstructor r -> r EmptyField r -> r EmptyGeneralize r -> r EmptyInstance r -> r EmptyMacro r -> r EmptyMutual r -> r EmptyPostulate r -> r EmptyPrimitive r -> r EmptyPrivate r -> r HiddenGeneralize r -> r InvalidCatchallPragma r -> r InvalidConstructor r -> r InvalidConstructorBlock r -> r InvalidCoverageCheckPragma r -> r InvalidNoPositivityCheckPragma r -> r InvalidNoUniverseCheckPragma r -> r InvalidRecordDirective r -> r InvalidTerminationCheckPragma r -> r MissingDeclarations xs -> getRange xs MissingDefinitions xs -> getRange xs NotAllowedInMutual r x -> r OpenPublicAbstract r -> r OpenPublicPrivate r -> r PolarityPragmasButNotPostulates xs -> getRange xs PragmaCompiled r -> r PragmaNoTerminationCheck r -> r SafeFlagEta r -> r SafeFlagInjective r -> r SafeFlagNoCoverageCheck r -> r SafeFlagNoPositivityCheck r -> r SafeFlagNoUniverseCheck r -> r SafeFlagNonTerminating r -> r SafeFlagPolarity r -> r SafeFlagTerminating r -> r ShadowingInTelescope ns -> getRange ns UnknownFixityInMixfixDecl xs -> getRange xs UnknownNamesInFixityDecl xs -> getRange xs UnknownNamesInPolarityPragmas xs -> getRange xs UselessAbstract r -> r UselessInstance r -> r UselessPrivate r -> r -- These error messages can (should) be terminated by a dot ".", -- there is no error context printed after them. instance Pretty DeclarationException' where pretty (MultipleEllipses p) = fsep $ pwords "Multiple ellipses in left-hand side" ++ [pretty p] pretty (InvalidName x) = fsep $ pwords "Invalid name:" ++ [pretty x] pretty (DuplicateDefinition x) = fsep $ pwords "Duplicate definition of" ++ [pretty x] pretty (DuplicateAnonDeclaration _) = fsep $ pwords "Duplicate declaration of _" pretty (MissingWithClauses x lhs) = fsep $ pwords "Missing with-clauses for function" ++ [pretty x] pretty (WrongDefinition x k k') = fsep $ pretty x : pwords ("has been declared as a " ++ prettyShow k ++ ", but is being defined as a " ++ prettyShow k') pretty (AmbiguousFunClauses lhs xs) = sep [ fsep $ pwords "More than one matching type signature for left hand side " ++ [pretty lhs] ++ pwords "it could belong to any of:" , vcat $ fmap (pretty . PrintRange) xs ] pretty (AmbiguousConstructor _ n ns) = sep [ fsep (pwords "Could not find a matching data signature for constructor " ++ [pretty n]) , vcat (case ns of [] -> [fsep $ pwords "There was no candidate."] _ -> fsep (pwords "It could be any of:") : fmap (pretty . PrintRange) ns ) ] pretty (WrongContentBlock b _) = fsep . pwords $ case b of PostulateBlock -> "A `postulate` block can only contain type signatures, possibly under keywords `instance` and `private`" DataBlock -> "A data definition can only contain type signatures, possibly under keyword instance" _ -> "Unexpected declaration" pretty (InvalidMeasureMutual _) = fsep $ pwords "In a mutual block, either all functions must have the same (or no) termination checking pragma." pretty (UnquoteDefRequiresSignature xs) = fsep $ pwords "Missing type signatures for unquoteDef" ++ map pretty (List1.toList xs) pretty (BadMacroDef nd) = fsep $ text (declName nd) : pwords "are not allowed in macro blocks" pretty (DeclarationPanic s) = text s pretty (UnfoldingOutsideOpaque _) = fsep . pwords $ "Unfolding declarations can only appear as the first declaration immediately contained in an opaque block." pretty (OpaqueInMutual _) = fsep $ pwords "Opaque blocks can not participate in mutual recursion. If the opaque definitions are to be mutually recursive, move the `mutual` block inside the `opaque` block." pretty (DisallowedInterleavedMutual _ what xs) = vcat $ List1.concat [ singleton $ fsep $ pwords "The following names are declared, but not accompanied by a definition:" -- Andreas, 2023-09-07, issue #6823: print also the range. -- Print a bullet list; thus, the plural version of this error message is sufficient. , fmap (("-" <+>) . pretty . PrintRange) xs , singleton $ fwords $ "Since " ++ what ++ " can not participate in mutual recursion, their definition must be given before this point." ] instance Pretty DeclarationWarning where pretty (DeclarationWarning _ w) = pretty w instance Pretty DeclarationWarning' where pretty = \case UnknownNamesInFixityDecl xs -> fsep $ pwords "The following names are not declared in the same scope as their syntax or fixity declaration (i.e., either not in scope at all, imported from another module, or declared in a super module):" ++ punctuate comma (map pretty xs) UnknownFixityInMixfixDecl xs -> fsep $ pwords "The following mixfix names do not have an associated fixity declaration:" ++ punctuate comma (map pretty xs) UnknownNamesInPolarityPragmas xs -> fsep $ pwords "The following names are not declared in the same scope as their polarity pragmas (they could for instance be out of scope, imported from another module, or declared in a super module):" ++ punctuate comma (map pretty xs) MissingDeclarations xs -> fsep $ pwords "The following names are defined but not accompanied by a declaration:" ++ punctuate comma (map (pretty . fst) xs) MissingDefinitions xs -> fsep $ pwords "The following names are declared but not accompanied by a definition:" ++ punctuate comma (map (pretty . fst) xs) NotAllowedInMutual r nd -> fsep $ text nd : pwords "in mutual blocks are not supported. Suggestion: get rid of the mutual block by manually ordering declarations" PolarityPragmasButNotPostulates xs -> fsep $ pwords "Polarity pragmas have been given for the following identifiers which are not postulates:" ++ punctuate comma (map pretty xs) UselessPrivate _ -> fsep $ pwords "Using private here has no effect. Private applies only to declarations that introduce new identifiers into the module, like type signatures and data, record, and module declarations." UselessAbstract _ -> fsep $ pwords "Using abstract here has no effect. Abstract applies to only definitions like data definitions, record type definitions and function clauses." UselessInstance _ -> fsep $ pwords "Using instance here has no effect. Instance applies only to declarations that introduce new identifiers into the module, like type signatures and axioms." EmptyMutual _ -> fsep $ pwords "Empty mutual block." EmptyConstructor{} -> fsep $ pwords "Empty constructor block." EmptyAbstract _ -> fsep $ pwords "Empty abstract block." EmptyPrivate _ -> fsep $ pwords "Empty private block." EmptyInstance _ -> fsep $ pwords "Empty instance block." EmptyMacro _ -> fsep $ pwords "Empty macro block." EmptyPostulate _ -> fsep $ pwords "Empty postulate block." EmptyGeneralize _ -> fsep $ pwords "Empty variable block." EmptyPrimitive _ -> fsep $ pwords "Empty primitive block." EmptyField _ -> fsep $ pwords "Empty field block." HiddenGeneralize _ -> fsep $ pwords "Declaring a variable as hidden has no effect in a variable block. Generalization never introduces visible arguments." InvalidRecordDirective{} -> fsep $ pwords "Record directives can only be used inside record definitions and before field declarations." InvalidTerminationCheckPragma _ -> fsep $ pwords "Termination checking pragmas can only precede a function definition or a mutual block (that contains a function definition)." InvalidConstructor{} -> fsep $ pwords "`constructor' blocks may only contain type signatures for constructors." InvalidConstructorBlock{} -> fsep $ pwords "No `constructor' blocks outside of `interleaved mutual' blocks." InvalidCoverageCheckPragma _ -> fsep $ pwords "Coverage checking pragmas can only precede a function definition or a mutual block (that contains a function definition)." InvalidNoPositivityCheckPragma _ -> fsep $ pwords "NO_POSITIVITY_CHECKING pragmas can only precede a data/record definition or a mutual block (that contains a data/record definition)." InvalidCatchallPragma _ -> fsep $ pwords "The CATCHALL pragma can only precede a function clause." InvalidNoUniverseCheckPragma _ -> fsep $ pwords "NO_UNIVERSE_CHECKING pragmas can only precede a data/record definition." PragmaNoTerminationCheck _ -> fsep $ pwords "Pragma {-# NO_TERMINATION_CHECK #-} has been removed. To skip the termination check, label your definitions either as {-# TERMINATING #-} or {-# NON_TERMINATING #-}." PragmaCompiled _ -> fsep $ pwords "COMPILE pragma not allowed in safe mode." OpenPublicAbstract _ -> fsep $ pwords "public does not have any effect in an abstract block." OpenPublicPrivate _ -> fsep $ pwords "public does not have any effect in a private block." ShadowingInTelescope nrs -> fsep $ pwords "Shadowing in telescope, repeated variable names:" ++ punctuate comma (fmap (pretty . fst) nrs) SafeFlagEta _ -> unsafePragma "ETA" SafeFlagInjective _ -> unsafePragma "INJECTIVE" SafeFlagNoCoverageCheck _ -> unsafePragma "NON_COVERING" SafeFlagNoPositivityCheck _ -> unsafePragma "NO_POSITIVITY_CHECK" SafeFlagNoUniverseCheck _ -> unsafePragma "NO_UNIVERSE_CHECK" SafeFlagNonTerminating _ -> unsafePragma "NON_TERMINATING" SafeFlagPolarity _ -> unsafePragma "POLARITY" SafeFlagTerminating _ -> unsafePragma "TERMINATING" where unsafePragma s = fsep $ ["Cannot", "use", s] ++ pwords "pragma with safe flag." instance NFData DeclarationWarning instance NFData DeclarationWarning'