{-# LANGUAGE CPP #-} {-| Functions for inserting implicit arguments at the right places. -} module Agda.TypeChecking.Implicit where import Control.Monad import Agda.Syntax.Common import Agda.Syntax.Internal as I import Agda.TypeChecking.Irrelevance import {-# SOURCE #-} Agda.TypeChecking.MetaVars import Agda.TypeChecking.Monad import Agda.TypeChecking.Reduce import Agda.TypeChecking.Substitute import Agda.TypeChecking.Pretty import Agda.Utils.Tuple #include "undefined.h" import Agda.Utils.Impossible -- | @implicitArgs n expand eti t@ generates up to @n@ implicit arguments -- metas (unbounded if @n<0@), as long as @t@ is a function type -- and @expand@ holds on the hiding info of its domain. -- -- If explicit arguments are to be inserted as well, they are -- inserted as instance arguments (used for recursive instance search). implicitArgs :: Int -> (Hiding -> Bool) -> Type -> TCM (Args, Type) implicitArgs n expand t = mapFst (map (fmap namedThing)) <$> do implicitNamedArgs n (\ h x -> expand h) t -- | @implicitNamedArgs n expand eti t@ generates up to @n@ named implicit arguments -- metas (unbounded if @n<0@), as long as @t@ is a function type -- and @expand@ holds on the hiding and name info of its domain. -- -- If explicit arguments are to be inserted as well, they are -- inserted as instance arguments (used for recursive instance search). implicitNamedArgs :: Int -> (Hiding -> ArgName -> Bool) -> Type -> TCM (NamedArgs, Type) implicitNamedArgs 0 expand t0 = return ([], t0) implicitNamedArgs n expand t0 = do t0' <- reduce t0 case unEl t0' of Pi (Dom info a) b | let x = absName b, expand (getHiding info) x -> do info' <- if hidden info then return info else do reportSDoc "tc.term.args.ifs" 15 $ text "inserting instance meta for type" <+> prettyTCM a return $ makeInstance info (_, v) <- newMetaArg info' x a let narg = Arg info (Named (Just $ unranged x) v) mapFst (narg :) <$> implicitNamedArgs (n-1) expand (absApp b v) _ -> return ([], t0') -- | Create a metavariable according to the 'Hiding' info. newMetaArg :: ArgInfo -- ^ Kind/relevance of meta. -> ArgName -- ^ Name suggestion for meta. -> Type -- ^ Type of meta. -> TCM (MetaId, Term) -- ^ The created meta as id and as term. newMetaArg info x a = do applyRelevanceToContext (getRelevance info) $ newMeta (getHiding info) (argNameToString x) a where newMeta :: Hiding -> String -> Type -> TCM (MetaId, Term) newMeta Instance{} = newIFSMeta newMeta Hidden = newNamedValueMeta RunMetaOccursCheck newMeta NotHidden = newNamedValueMeta RunMetaOccursCheck -- | Create a questionmark according to the 'Hiding' info. newInteractionMetaArg :: ArgInfo -- ^ Kind/relevance of meta. -> ArgName -- ^ Name suggestion for meta. -> Type -- ^ Type of meta. -> TCM (MetaId, Term) -- ^ The created meta as id and as term. newInteractionMetaArg info x a = do applyRelevanceToContext (getRelevance info) $ newMeta (getHiding info) (argNameToString x) a where newMeta :: Hiding -> String -> Type -> TCM (MetaId, Term) newMeta Instance{} = newIFSMeta newMeta Hidden = newNamedValueMeta' RunMetaOccursCheck newMeta NotHidden = newNamedValueMeta' RunMetaOccursCheck --------------------------------------------------------------------------- data ImplicitInsertion = ImpInsert [Hiding] -- ^ this many implicits have to be inserted | BadImplicits -- ^ hidden argument where there should have been a non-hidden arg | NoSuchName ArgName -- ^ bad named argument | NoInsertNeeded deriving (Show) impInsert :: [Hiding] -> ImplicitInsertion impInsert [] = NoInsertNeeded impInsert hs = ImpInsert hs -- | The list should be non-empty. insertImplicit :: NamedArg e -> [Arg ArgName] -> ImplicitInsertion insertImplicit _ [] = __IMPOSSIBLE__ insertImplicit a ts | visible a = impInsert $ nofHidden ts where nofHidden :: [Arg a] -> [Hiding] nofHidden = takeWhile notVisible . map getHiding insertImplicit a ts = case nameOf (unArg a) of Nothing -> maybe BadImplicits impInsert $ upto (getHiding a) $ map getHiding ts Just x -> find [] (rangedThing x) (getHiding a) ts where upto h [] = Nothing upto h (NotHidden : _) = Nothing upto h (h' : _) | sameHiding h h' = Just [] upto h (h' : hs) = (h' :) <$> upto h hs find :: [Hiding] -> ArgName -> Hiding -> [Arg ArgName] -> ImplicitInsertion find _ x _ (a@(Arg{}) : _) | visible a = NoSuchName x find hs x hidingx (a@(Arg _ y) : ts) | x == y && sameHiding hidingx a = impInsert $ reverse hs | x == y && sameHiding hidingx a = BadImplicits | otherwise = find (getHiding a : hs) x hidingx ts find i x _ [] = NoSuchName x