1 {-# LANGUAGE ExistentialQuantification #-}
2 {-# LANGUAGE PolyKinds #-}
3 {-# LANGUAGE StandaloneDeriving #-}
4 {-# LANGUAGE UndecidableInstances #-}
5 {-# OPTIONS_GHC -fno-warn-orphans #-}
7 module Symantic.Typer.Unify where
9 import Control.Monad (Monad (..))
10 import Data.Bool (otherwise)
11 import Data.Either (Either (..))
12 import Data.Eq (Eq (..))
13 import Data.Function (id, ($))
14 import Data.Functor ((<$>))
15 import Data.Map.Strict (Map)
16 import Data.Map.Strict qualified as Map
17 import Data.Maybe (Maybe (..))
18 import Data.Monoid (Monoid (..))
19 import Data.Semigroup (Semigroup (..))
20 import Text.Show (Show)
21 import Type.Reflection ((:~~:) (HRefl))
22 import Unsafe.Coerce (unsafeCoerce)
23 import Prelude qualified
25 import Symantic.Parser.Error (ErrorInj (..))
26 import Symantic.Typer.Eq (EqTy (eqTy))
27 import Symantic.Typer.Type (
31 Ty (TyApp, TyConst, TyVar, tyConst, tyVar),
44 -- | /Type variable substitution/.
46 -- WARNING: a 'Subst' MUST be without loops, and fully expanded.
48 = Subst (Map IndexVar (VT meta vs))
50 deriving instance (Show meta, Monoid meta) => Show (Subst meta vs)
51 instance Monoid meta => Semigroup (Subst meta vs) where
53 instance Monoid meta => Monoid (Subst meta vs) where
54 mempty = Subst Map.empty
57 -- | Unify two 'Subst's.
59 -- NOTE: the union is left-biased: in case of duplicate 'Var's,
60 -- it keeps the one from the first 'Subst' given.
62 -- NOTE: the first 'Subst' given is applied to the second (with 'subst'),
63 -- this way each 'Var' directly maps to an expanded 'Type',
64 -- so that, when using the resulting 'Subst',
65 -- there is no need to apply it multiple times
66 -- until there is no more substitution to be done.
67 unionSubst :: Subst meta vs -> Subst meta vs -> Subst meta vs
68 unionSubst sx@(Subst x) (Subst y) = Subst $ x `Map.union` ((\(VT v r) -> VT v $ subst sx r) Data.Functor.<$> y)
72 -- | A 'Var' and a 'Type' existentialized over their type index.
73 data VT meta vs = forall t. VT (Var meta vs t) (Ty meta vs t)
75 deriving instance (Show meta, Monoid meta) => Show (VT meta vs)
77 insertSubst :: Monoid meta => Var meta vs v -> Ty meta vs v -> Subst meta vs -> Subst meta vs
78 insertSubst v t (Subst s) = Subst $ Map.insert (indexVar v) (VT v t) s
80 lookupSubst :: Monoid meta => Var meta vs v -> Subst meta vs -> Maybe (Ty meta vs v)
81 lookupSubst v (Subst s)
82 | Just (VT v' t) <- Map.lookup (indexVar v) s
83 , Just HRefl <- v `eqTy` v' =
85 lookupSubst _v _m = Nothing
87 -- * Class 'Substable'
88 class Substable t where
89 -- | Like 'substVar', but without the /occurence check/.
91 Var meta vs v -> Ty meta vs v -> t meta vs a -> t meta vs a
93 -- | Substitute all the 'Var's which have a match in given 'Subst'.
95 Subst meta vs -> t meta vs a -> t meta vs a
96 instance Substable Ty where
97 substVarUnsafe _v _r t@TyConst{} = t
98 substVarUnsafe v r (TyApp f a) =
100 (substVarUnsafe v r f)
101 (substVarUnsafe v r a)
102 substVarUnsafe v r t@TyVar{tyVar = tv} =
107 -- substVarUnsafe v r (TyFam meta len fam as) =
108 -- TyFam meta len fam $ substVarUnsafe v r as
110 subst _s t@TyConst{} = t
111 subst s (TyApp f a) = TyApp (subst s f) (subst s a)
112 subst (Subst s) t@TyVar{tyVar = tv} =
113 case Map.lookup (indexVar tv) s of
117 Nothing -> Prelude.error "[BUG] subst: kind mismatch"
120 -- subst s (TyFam meta len fam as) = TyFam meta len fam $ subst s as
121 instance Substable (Tys as) where
122 substVarUnsafe _v _r TysZ = TysZ
123 substVarUnsafe v r (TysS t ts) =
125 `TysS` substVarUnsafe v r ts
127 subst s (TysS t ts) = subst s t `TysS` subst s ts
129 -- | Substitute the given 'Var' by the given 'Type',
130 -- returning 'Nothing' if this 'Type' contains
131 -- the 'Var' (occurence check).
141 then Nothing -- NOTE: occurence check
142 else Just $ substVarUnsafe v r t
144 -- ** Type 'ErrorUnify'
146 -- | Reasons why two 'Type's cannot be unified.
148 = -- | /occurence check/: a 'Var' is unified with a 'Type'
149 -- which contains this same 'Var'.
150 ErrorUnifyVarLoop IndexVar (TyVT meta)
151 | -- | Two 'TyConst's should be the same, but are different.
152 ErrorUnifyConst (TyVT meta) (TyVT meta)
153 | -- | Two 'Kind's should be the same, but are different.
154 ErrorUnifyKind (KindK meta) (KindK meta) (TyVT meta) (TyVT meta)
155 | -- | Cannot unify those two 'Type's.
156 ErrorUnifyType (TyVT meta) (TyVT meta)
158 deriving instance Monoid meta => Eq (ErrorUnify meta)
159 deriving instance (Show meta, Monoid meta) => Show (ErrorUnify meta)
161 instance ErrorInj (ErrorUnify meta) (ErrorUnify meta) where
164 data SourceTypeArg meta
165 = SourceTypeArg (TyVT meta)
167 -- | Return the left spine of a 'Ty':
168 -- the root 'Ty' and its 'Ty' parameters,
169 -- from the left to the right.
172 -- MC.MonadWriter (SourceTypeArg meta) (Sourced meta) =>
174 (TyT meta vs, [TyT meta vs])
177 go :: forall kx (x :: kx). [TyT meta vs] -> Ty meta vs x -> (TyT meta vs, [TyT meta vs])
178 -- Skip the constraint @q@.
179 go ctx (TyApp (TyApp (TyConst{tyConst = c}) _q) t)
180 | Just HRefl <- proj_ConstKi @_ @(#>) c =
182 -- Add a type to the spine.
183 go ctx (TyApp f a) = go (TyT a {-(SourceTypeArg (TyVT ty)-} : ctx) f
185 go ctx t = (TyT t {-SourceTypeArg (TyVT ty)-}, ctx)
187 -- | Return the /most general unification/ of two 'Type's, when it exists.
189 forall xyK (x :: xyK) (y :: xyK) vs meta.
193 Ty meta vs (x :: xyK) ->
194 Ty meta vs (y :: xyK) ->
195 Either (ErrorUnify meta) (Subst meta vs)
197 case (spineTy x, spineTy y) of
198 ((TyT xRootTy, px), (TyT yRootTy, py)) ->
199 case (xRootTy, yRootTy) of
200 (TyVar{tyVar = xV}, _) | Just HRefl <- xK `eqTy` kindOf xV -> goVar vs xV y
201 (_, TyVar{tyVar = yV}) | Just HRefl <- xK `eqTy` kindOf yV -> goVar vs yV x
202 (TyConst{tyConst = cx}, TyConst{tyConst = cy})
203 | Just HRefl <- cx `eqTy` cy -> goZip vs px py
204 | otherwise -> Left $ ErrorUnifyConst (TyVT xRootTy) (TyVT yRootTy)
205 _ -> Left $ ErrorUnifyType (TyVT x) (TyVT y)
209 forall k (a :: k) (b :: k) ws.
213 Either (ErrorUnify meta) (Subst meta ws)
215 case va `lookupSubst` sub of
216 Just a -> unifyType sub b a
218 case sub `subst` b of
219 TyVar{tyVar = vb} | Just HRefl <- va `eqTy` vb -> Right sub
221 | va `varOccursIn` b' -> Left $ ErrorUnifyVarLoop (indexVar va) (TyVT b')
222 | HRefl :: a :~~: b <- unsafeCoerce HRefl ->
223 Right $ insertSubst va b' mempty <> sub
229 Either (ErrorUnify meta) (Subst meta ws)
230 goZip sub [] [] = Right sub
231 goZip sub (TyT a : as) (TyT b : bs) =
233 Nothing -> Left $ ErrorUnifyKind (TyT aK) (TyT bK) (TyVT a) (TyVT b)
234 Just HRefl -> unifyType sub a b >>= \sub' -> goZip sub' as bs
238 goZip _vs _a _b = Prelude.error "[BUG] unifyType: kinds mismatch"