-- | Tools to manipulate patterns in abstract syntax -- in the TCM (type checking monad). module Agda.TypeChecking.Patterns.Abstract where import Control.Monad.Except import qualified Data.List as List import Data.Void import qualified Agda.Syntax.Abstract as A import Agda.Syntax.Abstract.Pattern import Agda.Syntax.Abstract.Views import Agda.Syntax.Concrete (FieldAssignment') import Agda.Syntax.Common import Agda.Syntax.Info as A import Agda.Syntax.Internal as I import Agda.Syntax.Literal import Agda.Syntax.Position import Agda.TypeChecking.Monad import Agda.TypeChecking.Warnings (raiseWarningsOnUsage) import Agda.Utils.Impossible -- | Expand literal integer pattern into suc/zero constructor patterns. -- expandLitPattern :: (MonadError TCErr m, MonadTCEnv m, ReadTCState m, HasBuiltins m) => A.Pattern -> m A.Pattern expandLitPattern = \case A.LitP info (LitNat n) | n < 0 -> negLit -- Andreas, issue #2365, negative literals not yet supported. | n > 20 -> tooBig | otherwise -> do Con z _ _ <- primZero Con s _ _ <- primSuc let r = getRange info let zero = A.ConP cinfo (unambiguous $ setRange r $ conName z) [] suc p = A.ConP cinfo (unambiguous $ setRange r $ conName s) [defaultNamedArg p] cinfo = A.ConPatInfo ConOCon info ConPatEager return $ foldr ($) zero $ List.genericReplicate n suc p -> return p where tooBig = typeError $ GenericError $ "Matching on natural number literals is done by expanding " ++ "the literal to the corresponding constructor pattern, so " ++ "you probably don't want to do it this way." negLit = typeError $ GenericError $ "Negative literals are not supported in patterns" -- | Expand away (deeply) all pattern synonyms in a pattern. -- Unfortunately, the more general type signature -- -- expandPatternSynonyms :: forall a p . APatternLike a p => p -> TCM p -- -- is rejected by GHC 7.10 -- -- Could not deduce (APatternLike A.Expr p) -- arising from a use of ‘postTraverseAPatternM’ -- -- I am mystified (Andreas, 2017-07-27) -- expandPatternSynonyms :: forall a p . APatternLike a p => p -> TCM p -- As a workaround, we define this function only for a = A.Exp, p = A.Pattern' -- and keep the type class ExpandPatternSynonyms (which would otherwise be superfluous). expandPatternSynonyms' :: forall e. A.Pattern' e -> TCM (A.Pattern' e) expandPatternSynonyms' = postTraverseAPatternM $ \case A.PatternSynP i x as -> setCurrentRange i $ do (ns, p) <- killRange <$> lookupPatternSyn x -- Andreas, 2020-02-11, issue #3734 -- If lookup of ambiguous pattern synonym was successful, -- we are justified to complain if one of the definitions -- involved in the resolution is tagged with a warning. -- This is less than optimal, since we do not rule out -- the invalid alternatives by typing, but we cannot do -- better here. mapM_ raiseWarningsOnUsage $ A.unAmbQ x -- Must expand arguments before instantiating otherwise pattern -- synonyms could get into dot patterns (which is __IMPOSSIBLE__). p <- expandPatternSynonyms' (vacuous p :: A.Pattern' e) case A.insertImplicitPatSynArgs (A.WildP . PatRange) (getRange x) ns as of Nothing -> typeError $ BadArgumentsToPatternSynonym x Just (_, _:_) -> typeError $ TooFewArgumentsToPatternSynonym x Just (s, []) -> do let subE _ = __IMPOSSIBLE__ -- No dot patterns in p return $ setRange (getRange i) $ substPattern' subE s p p -> return p class ExpandPatternSynonyms a where expandPatternSynonyms :: a -> TCM a default expandPatternSynonyms :: (Traversable f, ExpandPatternSynonyms b, f b ~ a) => a -> TCM a expandPatternSynonyms = traverse expandPatternSynonyms instance ExpandPatternSynonyms a => ExpandPatternSynonyms (Maybe a) instance ExpandPatternSynonyms a => ExpandPatternSynonyms [a] instance ExpandPatternSynonyms a => ExpandPatternSynonyms (Arg a) instance ExpandPatternSynonyms a => ExpandPatternSynonyms (Named n a) instance ExpandPatternSynonyms a => ExpandPatternSynonyms (FieldAssignment' a) instance ExpandPatternSynonyms (A.Pattern' e) where expandPatternSynonyms = expandPatternSynonyms'