{-# LANGUAGE CPP #-} {-# LANGUAGE MultiWayIf #-} module Agda.TypeChecking.Rules.Data where import Control.Monad import Data.List (genericTake) import Data.Maybe (fromMaybe) import qualified Agda.Syntax.Abstract as A import Agda.Syntax.Abstract.Views (deepUnscope) import Agda.Syntax.Internal import Agda.Syntax.Common import Agda.Syntax.Position import qualified Agda.Syntax.Info as Info import Agda.TypeChecking.Monad import Agda.TypeChecking.Constraints import Agda.TypeChecking.Conversion import Agda.TypeChecking.Substitute import Agda.TypeChecking.MetaVars import Agda.TypeChecking.Reduce import Agda.TypeChecking.Pretty import Agda.TypeChecking.Free import Agda.TypeChecking.Forcing import Agda.TypeChecking.Irrelevance import Agda.TypeChecking.Telescope import {-# SOURCE #-} Agda.TypeChecking.Rules.Term ( isType_ ) import Agda.Interaction.Options import Agda.Utils.Except import Agda.Utils.List import Agda.Utils.Size #include "undefined.h" import Agda.Utils.Impossible --------------------------------------------------------------------------- -- * Datatypes --------------------------------------------------------------------------- -- | Type check a datatype definition. Assumes that the type has already been -- checked. checkDataDef :: Info.DefInfo -> QName -> [A.LamBinding] -> [A.Constructor] -> TCM () checkDataDef i name ps cs = traceCall (CheckDataDef (getRange name) (qnameName name) ps cs) $ do -- TODO!! (qnameName) -- Add the datatype module addSection (qnameToMName name) -- Look up the type of the datatype. t <- instantiateFull =<< typeOfConst name -- Make sure the shape of the type is visible let unTelV (TelV tel a) = telePi tel a t <- unTelV <$> telView t -- Top level free vars freeVars <- getContextSize -- The parameters are in scope when checking the constructors. dataDef <- bindParameters ps t $ \tel t0 -> do -- Parameters are always hidden in constructors let tel' = hideAndRelParams <$> tel -- let tel' = hideTel tel -- The type we get from bindParameters is Θ -> s where Θ is the type of -- the indices. We count the number of indices and return s. -- We check that s is a sort. let TelV ixTel s0 = telView' t0 nofIxs = size ixTel s <- workOnTypes $ do -- Andreas, 2016-11-02 issue #2290 -- Trying to unify the sort with a fresh sort meta which is -- defined outside the index telescope is the most robust way -- to check independence of the indices. -- However, it might give the dreaded "Cannot instantiate meta..." -- error which we replace by a more understandable error -- in case of a suspected dependency. -- Jesper, 2017-09-14: since Set i depends non-strictly on i, -- we need to create the new meta in a nonstrict context. s <- applyRelevanceToContext NonStrict newSortMetaBelowInf catchError_ (addContext ixTel $ equalType s0 $ raise nofIxs $ sort s) $ \ err -> if any (`freeIn` s0) [0..nofIxs - 1] then typeError . GenericDocError =<< fsep [ text "The sort of" <+> prettyTCM name , text "cannot depend on its indices in the type" , prettyTCM t0 ] else throwError err return s reportSDoc "tc.data.sort" 20 $ vcat [ text "checking datatype" <+> prettyTCM name , nest 2 $ vcat [ text "type (parameters instantiated): " <+> prettyTCM t0 , text "type (full): " <+> prettyTCM t , text "sort: " <+> prettyTCM s , text "indices:" <+> text (show nofIxs) , text "params:" <+> text (show $ deepUnscope ps) ] ] let npars = size tel -- Change the datatype from an axiom to a datatype with no constructors. let dataDef = Datatype { dataPars = npars , dataIxs = nofIxs , dataInduction = Inductive , dataClause = Nothing , dataCons = [] -- Constructors are added later , dataSort = s , dataAbstr = Info.defAbstract i , dataMutual = Nothing } escapeContext npars $ do addConstant name $ defaultDefn defaultArgInfo name t dataDef -- polarity and argOcc.s determined by the positivity checker -- Check the types of the constructors mapM_ (checkConstructor name tel' nofIxs s) cs -- Return the data definition return dataDef let s = dataSort dataDef cons = map A.axiomName cs -- get constructor names -- If proof irrelevance is enabled we have to check that datatypes in -- Prop contain at most one element. do proofIrr <- proofIrrelevance case (proofIrr, s, cs) of (True, Prop, _:_:_) -> setCurrentRange cons $ typeError PropMustBeSingleton _ -> return () -- Add the datatype to the signature with its constructors. -- It was previously added without them. addConstant name $ defaultDefn defaultArgInfo name t $ dataDef{ dataCons = cons } -- | Ensure that the type is a sort. -- If it is not directly a sort, compare it to a 'newSortMetaBelowInf'. forceSort :: Type -> TCM Sort forceSort t = case unEl t of Sort s -> return s _ -> do -- Universes depend non-strictly on their argument s <- applyRelevanceToContext NonStrict newSortMetaBelowInf equalType t (sort s) return s -- | Type check a constructor declaration. Checks that the constructor targets -- the datatype and that it fits inside the declared sort. -- Returns the non-linear parameters. checkConstructor :: QName -- ^ Name of data type. -> Telescope -- ^ Parameter telescope. -> Nat -- ^ Number of indices of the data type. -> Sort -- ^ Sort of the data type. -> A.Constructor -- ^ Constructor declaration (type signature). -> TCM () checkConstructor d tel nofIxs s (A.ScopedDecl scope [con]) = do setScope scope checkConstructor d tel nofIxs s con checkConstructor d tel nofIxs s con@(A.Axiom _ i ai Nothing c e) = traceCall (CheckConstructor d tel s con) $ do {- WRONG -- Andreas, 2011-04-26: the following happens to the right of ':' -- we may use irrelevant arguments in a non-strict way in types t' <- workOnTypes $ do -} debugEnter c e -- check that we are relevant case getRelevance ai of Relevant -> return () Irrelevant -> typeError $ GenericError $ "Irrelevant constructors are not supported" _ -> __IMPOSSIBLE__ -- check that the type of the constructor is well-formed t <- workOnTypes $ isType_ e -- check that the type of the constructor ends in the data type n <- getContextSize debugEndsIn t d n constructs n t d -- compute which constructor arguments are forced forcedArgs <- computeForcingAnnotations t -- check that the sort (universe level) of the constructor type -- is contained in the sort of the data type -- (to avoid impredicative existential types) debugFitsIn s arity <- fitsIn forcedArgs t s debugAdd c t -- add parameters to constructor type and put into signature let con = ConHead c Inductive [] -- data constructors have no projectable fields and are always inductive escapeContext (size tel) $ addConstant c $ defaultDefn defaultArgInfo c (telePi tel t) $ Constructor { conPars = size tel , conArity = arity , conSrcCon = con , conData = d , conAbstr = Info.defAbstract i , conInd = Inductive , conForced = forcedArgs , conErased = [] -- computed during compilation to treeless } -- Add the constructor to the instance table, if needed when (Info.defInstance i == InstanceDef) $ do addNamedInstance c d where debugEnter c e = reportSDoc "tc.data.con" 5 $ vcat [ text "checking constructor" <+> prettyTCM c <+> text ":" <+> prettyTCM e ] debugEndsIn t d n = reportSDoc "tc.data.con" 15 $ vcat [ sep [ text "checking that" , nest 2 $ prettyTCM t , text "ends in" <+> prettyTCM d ] , nest 2 $ text "nofPars =" <+> text (show n) ] debugFitsIn s = reportSDoc "tc.data.con" 15 $ sep [ text "checking that the type fits in" , nest 2 $ prettyTCM s ] debugAdd c t = reportSDoc "tc.data.con" 5 $ vcat [ text "adding constructor" <+> prettyTCM c <+> text ":" <+> prettyTCM t ] checkConstructor _ _ _ _ _ = __IMPOSSIBLE__ -- constructors are axioms -- | Bind the parameters of a datatype. -- -- We allow omission of hidden parameters at the definition site. -- Example: -- @ -- data D {a} (A : Set a) : Set a -- data D A where -- c : A -> D A -- @ bindParameters :: [A.LamBinding] -> Type -> (Telescope -> Type -> TCM a) -> TCM a bindParameters = bindParameters' [] -- | Auxiliary function for 'bindParameters'. bindParameters' :: [Type] -- ^ @n@ replicas of type if @LamBinding@s are @DomainFree@s -- that came from a @DomainFull@ of @n@ binders. -- Should be comsumed whenever a @DomainFree@s are consumed. -> [A.LamBinding] -- ^ Bindings from definition site. -> Type -- ^ Pi-type of bindings coming from signature site. -> (Telescope -> Type -> TCM a) -- ^ Continuation, accepting parameter telescope and rest of type. -- The parameters are part of the context when the continutation is invoked. -> TCM a bindParameters' _ [] a ret = ret EmptyTel a bindParameters' ts (A.DomainFull (A.TypedBindings _ (Arg info (A.TBind _ xs e))) : bs) a ret = do unless (null ts) __IMPOSSIBLE__ t <- workOnTypes $ isType_ e bindParameters' (t <$ xs) (map (mergeHiding . fmap (A.DomainFree info)) xs ++ bs) a ret bindParameters' _ (A.DomainFull (A.TypedBindings _ (Arg _ A.TLet{})) : _) _ _ = -- line break! __IMPOSSIBLE__ bindParameters' ts0 ps0@(A.DomainFree info x : ps) t ret = do case unEl t of -- Andreas, 2011-04-07 ignore relevance information in binding?! Pi arg@(Dom info' a) b -> do if | info == info' -> do -- Andreas, 2016-12-30, issue #1886: -- If type for binding is present, check its correctness. ts <- caseList ts0 (return []) $ \ t0 ts -> do equalType t0 a return ts continue ts ps $ A.unBind x | visible info, notVisible info' -> continue ts0 ps0 =<< freshName_ (absName b) | otherwise -> __IMPOSSIBLE__ -- Andreas, 2016-12-30 Concrete.Definition excludes this case where continue ts ps x = do addContext (x, arg) $ bindParameters' (raise 1 ts) ps (absBody b) $ \ tel s -> ret (ExtendTel arg $ Abs (nameToArgName x) tel) s _ -> __IMPOSSIBLE__ -- | Check that the arguments to a constructor fits inside the sort of the datatype. -- The first argument is the type of the constructor. -- -- As a side effect, return the arity of the constructor. fitsIn :: [IsForced] -> Type -> Sort -> TCM Int fitsIn forceds t s = do reportSDoc "tc.data.fits" 10 $ sep [ text "does" <+> prettyTCM t , text "of sort" <+> prettyTCM (getSort t) , text "fit in" <+> prettyTCM s <+> text "?" ] -- The code below would be simpler, but doesn't allow datatypes -- to be indexed by the universe level. -- s' <- instantiateFull (getSort t) -- noConstraints $ s' `leqSort` s t <- reduce t case unEl t of Pi dom b -> do withoutK <- optWithoutK <$> pragmaOptions let (forced,forceds') = nextIsForced forceds unless (isForced forced && not withoutK) $ do sa <- reduce $ getSort dom unless (sa == SizeUniv) $ sa `leqSort` s addContext (absName b, dom) $ do succ <$> fitsIn forceds' (absBody b) (raise 1 s) _ -> return 0 -- getSort t `leqSort` s -- Andreas, 2013-04-13 not necessary since constructor type ends in data type -- | Return the parameters that share variables with the indices -- nonLinearParameters :: Int -> Type -> TCM [Int] -- nonLinearParameters nPars t = -- | Check that a type constructs something of the given datatype. The first -- argument is the number of parameters to the datatype. -- constructs :: Int -> Type -> QName -> TCM () constructs nofPars t q = constrT 0 t where -- The number n counts the proper (non-parameter) constructor arguments. constrT :: Nat -> Type -> TCM () constrT n t = do t <- reduce t case unEl t of Pi _ (NoAbs _ b) -> constrT n b Pi a b -> underAbstraction a b $ constrT (n + 1) -- OR: addCxtString (absName b) a $ constrT (n + 1) (absBody b) Def d es | d == q -> do let vs = fromMaybe __IMPOSSIBLE__ $ allApplyElims es (pars, ixs) <- normalise $ splitAt nofPars vs -- check that the constructor parameters are the data parameters checkParams n pars MetaV{} -> do def <- getConstInfo q -- Analyse the type of q (name of the data type) let td = defType def TelV tel core <- telView td -- Construct the parameter arguments -- The parameters are @n + nofPars - 1 .. n@ let us = zipWith (\ arg x -> var x <$ arg ) (telToArgs tel) $ take nofPars $ downFrom (nofPars + n) -- The indices are fresh metas xs <- newArgsMeta =<< piApplyM td us let t' = El (dataSort $ theDef def) $ Def q $ map Apply $ us ++ xs -- Andreas, 2017-11-07, issue #2840 -- We should not postpone here, otherwise we might upset the positivity checker. noConstraints $ equalType t t' constrT n t' _ -> typeError $ ShouldEndInApplicationOfTheDatatype t checkParams n vs = zipWithM_ sameVar vs ps where nvs = size vs ps = genericTake nvs $ downFrom (n + nvs) sameVar arg i -- skip irrelevant parameters | isIrrelevant arg = return () | otherwise = do t <- typeOfBV i equalTerm t (unArg arg) (var i) {- UNUSED, Andreas 2012-09-13 -- | Force a type to be a specific datatype. forceData :: QName -> Type -> TCM Type forceData d (El s0 t) = liftTCM $ do t' <- reduce t d <- canonicalName d case t' of Def d' _ | d == d' -> return $ El s0 t' | otherwise -> fail $ "wrong datatype " ++ show d ++ " != " ++ show d' MetaV m vs -> do Defn {defType = t, theDef = Datatype{dataSort = s}} <- getConstInfo d ps <- newArgsMeta t noConstraints $ leqType (El s0 t') (El s (Def d ps)) -- TODO: need equalType? reduce $ El s0 t' _ -> typeError $ ShouldBeApplicationOf (El s0 t) d -} -- | Is the type coinductive? Returns 'Nothing' if the answer cannot -- be determined. isCoinductive :: Type -> TCM (Maybe Bool) isCoinductive t = do El s t <- reduce t case t of Def q _ -> do def <- getConstInfo q case theDef def of Axiom {} -> return (Just False) Function {} -> return Nothing Datatype { dataInduction = CoInductive } -> return (Just True) Datatype { dataInduction = Inductive } -> return (Just False) Record { recInduction = Just CoInductive } -> return (Just True) Record { recInduction = _ } -> return (Just False) Constructor {} -> __IMPOSSIBLE__ Primitive {} -> __IMPOSSIBLE__ AbstractDefn{} -> __IMPOSSIBLE__ Var {} -> return Nothing Lam {} -> __IMPOSSIBLE__ Lit {} -> __IMPOSSIBLE__ Level {} -> __IMPOSSIBLE__ Con {} -> __IMPOSSIBLE__ Pi {} -> return (Just False) Sort {} -> return (Just False) MetaV {} -> return Nothing DontCare{} -> __IMPOSSIBLE__