2
{-# LANGUAGE DeriveDataTypeable #-}
3
{-# LANGUAGE DeriveFoldable #-}
4
{-# LANGUAGE DeriveFunctor #-}
5
{-# LANGUAGE DeriveTraversable #-}
6
{-# LANGUAGE FlexibleInstances #-}
2
{-# LANGUAGE DeriveDataTypeable #-}
3
{-# LANGUAGE DeriveFoldable #-}
4
{-# LANGUAGE DeriveFunctor #-}
5
{-# LANGUAGE DeriveTraversable #-}
6
{-# LANGUAGE FlexibleInstances #-}
7
7
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8
{-# LANGUAGE MultiParamTypeClasses #-}
9
{-# LANGUAGE PatternGuards #-}
10
{-# LANGUAGE TupleSections #-}
11
{-# LANGUAGE TypeSynonymInstances #-}
8
{-# LANGUAGE MultiParamTypeClasses #-}
9
{-# LANGUAGE PatternGuards #-}
10
{-# LANGUAGE TupleSections #-}
11
{-# LANGUAGE TypeSynonymInstances #-}
13
13
module Agda.TypeChecking.Rules.LHS.Unify where
15
import Prelude hiding (null)
15
17
import Control.Arrow ((***))
16
18
import Control.Applicative hiding (empty)
17
19
import Control.Monad.State
18
20
import Control.Monad.Reader
19
import Control.Monad.Error
20
21
import Control.Monad.Writer (WriterT(..), MonadWriter(..), Monoid(..))
23
import Data.IntMap (IntMap)
24
import qualified Data.IntMap as IntMap
22
25
import Data.Map (Map)
23
26
import qualified Data.Map as Map
24
import Data.List hiding (sort)
27
import Data.List hiding (null, sort)
26
29
import Data.Typeable (Typeable)
27
30
import Data.Foldable (Foldable)
30
33
import Agda.Interaction.Options (optInjectiveTypeConstructors)
32
35
import Agda.Syntax.Common
33
import Agda.Syntax.Internal as I
36
import Agda.Syntax.Internal as I hiding (Substitution)
34
37
import Agda.Syntax.Literal
35
38
import Agda.Syntax.Position
42
45
import Agda.TypeChecking.DropArgs
43
46
import Agda.TypeChecking.Level (reallyUnLevelView)
44
47
import Agda.TypeChecking.Reduce
45
import Agda.TypeChecking.Pretty
48
import Agda.TypeChecking.Pretty hiding (empty)
49
import qualified Agda.TypeChecking.Pretty as P
46
50
import Agda.TypeChecking.Substitute hiding (Substitution)
47
51
import qualified Agda.TypeChecking.Substitute as S
48
52
import Agda.TypeChecking.Telescope
55
59
import Agda.TypeChecking.Rules.LHS.Problem
56
60
-- import Agda.TypeChecking.SyntacticEquality
62
import Agda.Utils.Except
63
( Error(noMsg, strMsg)
64
, MonadError(catchError, throwError)
58
67
import Agda.Utils.Maybe
68
import Agda.Utils.Monad
69
import Agda.Utils.Null
59
70
import Agda.Utils.Size
60
import Agda.Utils.Monad
62
#include "../../../undefined.h"
72
#include "undefined.h"
63
73
import Agda.Utils.Impossible
65
75
newtype Unify a = U { unUnify :: ReaderT UnifyEnv (WriterT UnifyOutput (ExceptionT UnifyException (StateT UnifyState TCM))) a }
79
89
instance HasConstInfo Unify where
80
90
getConstInfo = U . lift . lift . lift . lift . getConstInfo
93
------------------------------------------------------------------------
82
95
data UnifyMayPostpone = MayPostpone | MayNotPostpone
84
97
type UnifyEnv = UnifyMayPostpone
85
emptyUEnv = MayPostpone
100
emptyUEnv = MayPostpone
87
102
noPostponing :: Unify a -> Unify a
88
noPostponing (U (ReaderT f)) = U . ReaderT . const $ f MayNotPostpone
103
noPostponing = U . local (const MayNotPostpone) . unUnify
90
105
askPostpone :: Unify UnifyMayPostpone
91
askPostpone = U . ReaderT $ return
106
askPostpone = U $ ask
93
108
-- | Output the result of unification (success or maybe).
94
109
type UnifyOutput = Unifiable
96
emptyUOutput :: UnifyOutput
99
111
-- | Were two terms unifiable or did we have to postpone some equation such that we are not sure?
101
113
= Definitely -- ^ Unification succeeded.
134
146
noMsg = strMsg ""
135
147
strMsg = GenericUnifyException
137
data UnifyState = USt { uniSub :: Sub
138
, uniConstr :: [Equality]
149
data UnifyState = USt
151
, uniConstr :: [Equality]
141
emptyUState = USt Map.empty []
154
emptyUState :: UnifyState
155
emptyUState = USt IntMap.empty []
143
157
-- | Throw-away error message.
144
158
projectionMismatch :: QName -> QName -> Unify a
156
170
applySubst rho (Equal a s t) =
157
171
Equal (applySubst rho a) (applySubst rho s) (applySubst rho t)
159
onSub :: (Sub -> a) -> Unify a
160
onSub f = U $ gets $ f . uniSub
174
getSub = U $ gets uniSub
162
176
modSub :: (Sub -> Sub) -> Unify ()
163
177
modSub f = U $ modify $ \s -> s { uniSub = f $ uniSub s }
246
260
i |-> (u, a) = do
247
261
occursCheck i u a
248
262
liftTCM $ reportSDoc "tc.lhs.unify.assign" 15 $ prettyTCM (var i) <+> text ":=" <+> prettyTCM u
249
modSub $ Map.insert i (killRange u)
263
modSub $ IntMap.insert i (killRange u)
250
264
-- Apply substitution to itself (issue 552)
252
266
rho' <- traverse ureduce rho
253
267
modSub $ const rho'
255
269
makeSubstitution :: Sub -> S.Substitution
256
270
makeSubstitution sub
258
| otherwise = map val [0 .. highestIndex] ++# raiseS (highestIndex + 1)
272
| otherwise = map val [0 .. highestIndex] ++# raiseS (highestIndex + 1)
260
highestIndex = fst $ Map.findMax sub
261
val i = maybe (var i) id $ Map.lookup i sub
274
highestIndex = fst $ IntMap.findMax sub
275
val i = fromMaybe (var i) $ IntMap.lookup i sub
263
277
-- | Apply the current substitution on a term and reduce to weak head normal form.
264
278
class UReduce t where
267
281
instance UReduce Term where
268
282
ureduce u = doEtaContractImplicit $ do
269
rho <- onSub makeSubstitution
283
rho <- makeSubstitution <$> getSub
270
284
-- Andreas, 2013-10-24 the following call to 'normalise' is problematic
271
285
-- (see issue 924). Instead, we only normalize if unifyAtomHH is undecided.
272
286
-- liftTCM $ etaContract =<< normalise (applySubst rho u)
329
343
instantiate :: Nat -> Substitution -> Substitution
330
344
instantiate i s = map (fmap $ inst i u) s
348
-- @inst i u v@ replaces index @i@ in @v@ by @u@, without removing the index.
334
349
inst :: Nat -> Term -> Term -> Term
335
350
inst i u v = applySubst us v
336
351
where us = [var j | j <- [0..i - 1] ] ++# u :# raiseS (i + 1)
338
data UnificationResult = Unifies Substitution | NoUnify Type Term Term | DontKnow TCErr
353
data UnificationResult
354
= Unifies Substitution
355
| NoUnify Type Term Term
340
358
-- | Are we in a homogeneous (one type) or heterogeneous (two types) situation?
485
503
checkEqualities $ applySubst (makeSubstitution s) eqs
486
504
let n = maximum $ (-1) : flex'
487
return $ Unifies $ flattenSubstitution [ Map.lookup i s | i <- [0..n] ]
505
return $ Unifies $ flattenSubstitution [ IntMap.lookup i s | i <- [0..n] ]
488
506
`catchError` \err -> case err of
489
507
TypeError _ (Closure {clValue = WithoutKError{}}) -> throwError err
490
508
_ -> return $ DontKnow err
513
531
unifyConstructorArgs a12 vs1 vs2 = do
514
532
liftTCM $ reportSDoc "tc.lhs.unify" 15 $ sep
515
533
[ text "unifyConstructorArgs"
516
-- , nest 2 $ parens (prettyTCM tel0)
517
, nest 2 $ prettyList $ map prettyTCM vs1
518
, nest 2 $ prettyList $ map prettyTCM vs2
534
-- , nest 2 $ parens (prettyTCM tel0)
535
, nest 2 $ prettyList $ map prettyTCM vs1
536
, nest 2 $ prettyList $ map prettyTCM vs2
519
537
, nest 2 $ text "constructor type:" <+> prettyTCM a12
521
539
let n = genericLength vs1
540
558
unifyConArgs tel0@(ExtendTel a@(Dom _ bHH) tel) us0@(arg@(Arg _ u) : us) vs0@(Arg _ v : vs) = do
541
559
liftTCM $ reportSDoc "tc.lhs.unify" 15 $ sep
542
560
[ text "unifyConArgs"
543
-- , nest 2 $ parens (prettyTCM tel0)
544
, nest 2 $ prettyList $ map prettyTCM us0
545
, nest 2 $ prettyList $ map prettyTCM vs0
546
, nest 2 $ text "at telescope" <+> prettyTCM bHH <+> text "..."
561
-- , nest 2 $ parens (prettyTCM tel0)
562
, nest 2 $ prettyList $ map prettyTCM us0
563
, nest 2 $ prettyList $ map prettyTCM vs0
564
, nest 2 $ text "at telescope" <+> prettyTCM bHH <+> text "..."
548
566
liftTCM $ reportSDoc "tc.lhs.unify" 25 $
549
567
(text $ "tel0 = " ++ show tel0)
582
600
unifyElims a us0@(Apply arg@(Arg _ u) : us) vs0@(Apply (Arg _ v) : vs) = do
583
601
liftTCM $ reportSDoc "tc.lhs.unify" 15 $ sep
584
602
[ text "unifyElims"
585
, nest 2 $ parens (prettyTCM a)
586
, nest 2 $ prettyList $ map prettyTCM us0
587
, nest 2 $ prettyList $ map prettyTCM vs0
603
, nest 2 $ parens (prettyTCM a)
604
, nest 2 $ prettyList $ map prettyTCM us0
605
, nest 2 $ prettyList $ map prettyTCM vs0
589
607
a <- ureduce a -- Q: reduce sufficient?
590
608
case ignoreSharing $ unEl a of
592
610
-- Andreas, Ulf, 2011-09-08 (AIM XVI)
593
611
-- in case of dependent function type, we cannot postpone
594
612
-- unification of u and v, otherwise us or vs might be ill-typed
595
613
let dep = dependent $ unEl a
596
614
-- skip irrelevant parts
597
unless (isIrrelevant b) $
615
unless (isIrrelevant b) $
598
616
(if dep then noPostponing else id) $
599
617
unify (unDom b) u v
600
618
arg <- traverse ureduce arg
601
unifyElims (a `piApply` [arg]) us vs
619
unifyElims (a `piApply` [arg]) us vs
603
621
where dependent (Pi _ NoAbs{}) = False
604
622
dependent (Pi b c) = 0 `relevantIn` absBody c
605
623
dependent (Shared p) = dependent (derefPtr p)
613
631
unifyArgs a us0@(arg@(Arg _ u) : us) vs0@(Arg _ v : vs) = do
614
632
liftTCM $ reportSDoc "tc.lhs.unify" 15 $ sep
615
633
[ text "unifyArgs"
616
, nest 2 $ parens (prettyTCM a)
617
, nest 2 $ prettyList $ map prettyTCM us0
618
, nest 2 $ prettyList $ map prettyTCM vs0
634
, nest 2 $ parens (prettyTCM a)
635
, nest 2 $ prettyList $ map prettyTCM us0
636
, nest 2 $ prettyList $ map prettyTCM vs0
620
638
a <- ureduce a -- Q: reduce sufficient?
621
639
case ignoreSharing $ unEl a of
623
641
-- Andreas, Ulf, 2011-09-08 (AIM XVI)
624
642
-- in case of dependent function type, we cannot postpone
625
643
-- unification of u and v, otherwise us or vs might be ill-typed
626
644
let dep = dependent $ unEl a
627
645
-- skip irrelevant parts
628
unless (isIrrelevant b) $
646
unless (isIrrelevant b) $
629
647
(if dep then noPostponing else id) $
630
648
unify (unDom b) u v
631
649
arg <- traverse ureduce arg
632
unifyArgs (a `piApply` [arg]) us vs
650
unifyArgs (a `piApply` [arg]) us vs
634
652
where dependent (Pi _ NoAbs{}) = False
635
653
dependent (Pi b c) = 0 `relevantIn` absBody c
636
654
dependent (Shared p) = dependent (derefPtr p)
678
696
-> Term -> Term -> Unify ()
679
697
unifyHH aHH u v = do
680
698
liftTCM $ reportSDoc "tc.lhs.unify" 15 $
682
, nest 2 $ (parens $ prettyTCM u) <+> text "=?="
683
, nest 2 $ parens $ prettyTCM v
684
, nest 2 $ text ":" <+> prettyTCM aHH
700
, nest 2 $ (parens $ prettyTCM u) <+> text "=?="
701
, nest 2 $ parens $ prettyTCM v
702
, nest 2 $ text ":" <+> prettyTCM aHH
686
704
u <- liftTCM . constructorForm =<< ureduce u
687
705
v <- liftTCM . constructorForm =<< ureduce v
688
706
aHH <- ureduce aHH
689
707
liftTCM $ reportSDoc "tc.lhs.unify" 25 $
690
sep [ text "unifyHH (reduced)"
691
, nest 2 $ (parens $ prettyTCM u) <+> text "=?="
692
, nest 2 $ parens $ prettyTCM v
693
, nest 2 $ text ":" <+> prettyTCM aHH
708
sep [ text "unifyHH (reduced)"
709
, nest 2 $ (parens $ prettyTCM u) <+> text "=?="
710
, nest 2 $ parens $ prettyTCM v
711
, nest 2 $ text ":" <+> prettyTCM aHH
695
713
-- obtain the (== Size) function
696
714
isSizeName <- liftTCM isSizeNameTest
736
754
(|->?) = maybeAssign fallback
738
756
liftTCM $ reportSDoc "tc.lhs.unify" 15 $
739
sep [ text "unifyAtom"
740
, nest 2 $ prettyTCM u <> if flexibleTerm u then text " (flexible)" else empty
757
sep [ text "unifyAtom"
758
, nest 2 $ prettyTCM u <> if flexibleTerm u then text " (flexible)" else P.empty
741
759
, nest 2 $ text "=?="
742
, nest 2 $ prettyTCM v <> if flexibleTerm v then text " (flexible)" else empty
743
, nest 2 $ text ":" <+> prettyTCM aHH
760
, nest 2 $ prettyTCM v <> if flexibleTerm v then text " (flexible)" else P.empty
761
, nest 2 $ text ":" <+> prettyTCM aHH
745
763
liftTCM $ reportSDoc "tc.lhs.unify" 60 $
746
764
text $ "aHH = " ++ show aHH
747
765
case (ignoreSharing u, ignoreSharing v) of
753
771
(_, Level l) -> do
754
772
v <- liftTCM $ reallyUnLevelView l
755
773
unifyAtomHH aHH u v tryAgain
756
(Var i us, Var j vs) | i == j -> checkEqualityHH aHH u v
774
(Var i us, Var j vs) | i == j -> checkEqualityHH aHH u v
757
775
-- Andreas, 2013-03-05: the following flex/flex case is an attempt at
758
776
-- better dotting (see Issue811). Does not work perfectly, maybe the best choice
759
777
-- which variable to assign cannot made locally, but would need a look at the full
769
787
-- (in this order, see Problem.hs).
770
788
-- The comparison is total.
771
789
if fj >= fi then j |->? (u, a) else i |->? (v, a)
772
(Var i [], _) | homogeneous && flexible i -> i |->? (v, a)
773
(_, Var j []) | homogeneous && flexible j -> j |->? (u, a)
774
(Con c us, Con c' vs)
790
(Var i [], _) | homogeneous && flexible i -> i |->? (v, a)
791
(_, Var j []) | homogeneous && flexible j -> j |->? (u, a)
792
(Con c us, Con c' vs)
776
794
r <- liftTCM (dataOrRecordTypeHH' c aHH)
791
809
Nothing -> checkEqualityHH aHH u v
792
810
| otherwise -> constructorMismatchHH aHH u v
793
811
-- Definitions are ok as long as they can't reduce (i.e. datatypes/axioms)
794
(Def d us, Def d' vs)
812
(Def d us, Def d' vs)
796
814
-- d must be a data, record or axiom
797
815
def <- getConstInfo d