1 {-# LANGUAGE ExistentialQuantification #-}
2 {-# LANGUAGE PolyKinds #-}
3 {-# LANGUAGE QuantifiedConstraints #-}
4 {-# LANGUAGE ScopedTypeVariables #-}
5 {-# LANGUAGE StandaloneDeriving #-}
6 {-# LANGUAGE UndecidableInstances #-}
7 {-# OPTIONS_GHC -fno-warn-orphans #-}
9 module Symantic.Typer.Unify where
11 import Control.Monad (Monad (..))
12 import Data.Bool (otherwise)
13 import Data.Either (Either (..))
14 import Data.Eq (Eq (..))
15 import Data.Function (id, ($))
16 import Data.Functor ((<$>))
17 import Data.Map.Strict (Map)
18 import Data.Map.Strict qualified as Map
19 import Data.Maybe (Maybe (..))
20 import Data.Monoid (Monoid (..))
21 import Data.Semigroup (Semigroup (..))
22 import Text.Show (Show)
23 import Type.Reflection ((:~~:) (HRefl))
24 import Unsafe.Coerce (unsafeCoerce)
25 import Prelude qualified
27 import Symantic.Parser.Error (ErrorInj (..))
28 import Symantic.Typer.Eq (EqTy (eqTy))
29 import Symantic.Typer.Type
33 -- | /Type variable substitution/.
35 -- WARNING: a 'Subst' MUST be without loops, and fully expanded.
37 = Subst (Map IndexVar (VT prov vs))
39 deriving instance (Show prov) => Show (Subst prov vs)
40 instance Semigroup (Subst prov vs) where
42 instance Monoid (Subst prov vs) where
43 mempty = Subst Map.empty
46 -- | Unify two 'Subst's.
48 -- NOTE: the union is left-biased: in case of duplicate 'Var's,
49 -- it keeps the one from the first 'Subst' given.
51 -- NOTE: the first 'Subst' given is applied to the second (with 'subst'),
52 -- this way each 'Var' directly maps to an expanded 'Type',
53 -- so that, when using the resulting 'Subst',
54 -- there is no need to apply it multiple times
55 -- until there is no more substitution to be done.
56 unionSubst :: Subst prov vs -> Subst prov vs -> Subst prov vs
57 unionSubst sx@(Subst x) (Subst y) = Subst $ x `Map.union` ((\(VT v r) -> VT v $ subst sx r) Data.Functor.<$> y)
61 -- | A 'Var' and a 'Type' existentialized over their type index.
62 data VT prov vs = forall t. VT (Var prov vs t) (Ty prov vs t)
64 deriving instance (Show prov) => Show (VT prov vs)
66 insertSubst :: Var prov vs v -> Ty prov vs v -> Subst prov vs -> Subst prov vs
67 insertSubst v t (Subst s) = Subst $ Map.insert (indexVar v) (VT v t) s
69 lookupSubst :: Var prov vs v -> Subst prov vs -> Maybe (Ty prov vs v)
70 lookupSubst v (Subst s)
71 | Just (VT v' t) <- Map.lookup (indexVar v) s
72 , Just HRefl <- v `eqTy` v' =
74 lookupSubst _v _m = Nothing
76 -- * Class 'Substable'
77 class Substable t where
78 -- | Like 'substVar', but without the /occurence check/.
80 Var prov vs v -> Ty prov vs v -> t prov vs a -> t prov vs a
82 -- | Substitute all the 'Var's which have a match in given 'Subst'.
84 Subst prov vs -> t prov vs a -> t prov vs a
85 instance Substable Ty where
86 substVarUnsafe _v _r t@TyConst{} = t
87 substVarUnsafe v r ty@TyProv{tyUnProv} =
88 ty{tyUnProv = substVarUnsafe v r tyUnProv}
89 substVarUnsafe v r (TyApp f a) =
91 (substVarUnsafe v r f)
92 (substVarUnsafe v r a)
93 substVarUnsafe v r t@TyVar{tyVar = tv} =
98 -- substVarUnsafe v r (TyFam prov len fam as) =
99 -- TyFam prov len fam $ substVarUnsafe v r as
101 subst _s t@TyConst{} = t
102 subst s ty@TyProv{tyUnProv} = ty{tyUnProv = subst s tyUnProv}
103 subst s (TyApp f a) = TyApp (subst s f) (subst s a)
104 subst (Subst s) t@TyVar{tyVar = tv} =
105 case Map.lookup (indexVar tv) s of
109 Nothing -> Prelude.error "[BUG] subst: kind mismatch"
112 -- subst s (TyFam prov len fam as) = TyFam prov len fam $ subst s as
113 instance Substable (Tys as) where
114 substVarUnsafe _v _r TysZ = TysZ
115 substVarUnsafe v r (TysS t ts) =
117 `TysS` substVarUnsafe v r ts
119 subst s (TysS t ts) = subst s t `TysS` subst s ts
121 -- | Substitute the given 'Var' by the given 'Type',
122 -- returning 'Nothing' if this 'Type' contains
123 -- the 'Var' (occurence check).
133 then Nothing -- NOTE: occurence check
134 else Just $ substVarUnsafe v r t
136 -- ** Type 'ErrorUnify'
138 -- | Reasons why two 'Type's cannot be unified.
140 = -- | /occurence check/: a 'Var' is unified with a 'Type'
141 -- which contains this same 'Var'.
142 ErrorUnifyVarLoop IndexVar (TyVT prov)
143 | -- | Two 'TyConst's should be the same, but are different.
144 ErrorUnifyConst (TyVT prov) (TyVT prov)
145 | -- | Two 'Kind's should be the same, but are different.
146 ErrorUnifyKind (KindK prov) (KindK prov) (TyVT prov) (TyVT prov)
147 | -- | Cannot unify those two 'Type's.
148 ErrorUnifyType (TyVT prov) (TyVT prov)
150 deriving instance Eq (ErrorUnify prov)
151 deriving instance (Show prov) => Show (ErrorUnify prov)
153 instance ErrorInj (ErrorUnify prov) (ErrorUnify prov) where
156 data SourceTypeArg prov
157 = SourceTypeArg (TyVT prov)
159 -- | Return the left spine of a 'Ty':
160 -- the root 'Ty' and its 'Ty' parameters,
161 -- from the left to the right.
164 -- MC.MonadWriter (SourceTypeArg prov) (Sourced prov) =>
166 (TyT prov vs, [TyT prov vs])
169 go :: forall kx (x :: kx). [TyT prov vs] -> Ty prov vs x -> (TyT prov vs, [TyT prov vs])
170 -- Skip the constraint @q@.
171 go ctx (TyApp (TyApp (TyConst{tyConst = c}) _q) t)
172 | Just HRefl <- proj_ConstKi @_ @(#>) c =
174 -- Add a type to the spine.
175 go ctx (TyApp f a) = go (TyT a {-(SourceTypeArg (TyVT ty)-} : ctx) f
177 go ctx t = (TyT t {-SourceTypeArg (TyVT ty)-}, ctx)
179 -- | Return the /most general unification/ of two 'Type's, when it exists.
181 forall xyK (x :: xyK) (y :: xyK) vs prov.
182 (forall k. ProvenanceKindOf (Ty @k) prov) =>
183 (forall k. ProvenanceKindOf (Var @k) prov) =>
186 Ty prov vs (x :: xyK) ->
187 Ty prov vs (y :: xyK) ->
188 Either (ErrorUnify prov) (Subst prov vs)
190 case (spineTy x, spineTy y) of
191 ((TyT xRootTy, px), (TyT yRootTy, py)) ->
192 case (xRootTy, yRootTy) of
193 (TyVar{tyVar = xV}, _) | Just HRefl <- xK `eqTy` kindOf xV -> goVar vs xV y
194 (_, TyVar{tyVar = yV}) | Just HRefl <- xK `eqTy` kindOf yV -> goVar vs yV x
195 (TyConst{tyConst = cx}, TyConst{tyConst = cy})
196 | Just HRefl <- cx `eqTy` cy -> goZip vs px py
197 | otherwise -> Left $ ErrorUnifyConst (TyVT xRootTy) (TyVT yRootTy)
198 _ -> Left $ ErrorUnifyType (TyVT x) (TyVT y)
202 forall k (a :: k) (b :: k) ws.
203 (forall k'. ProvenanceKindOf (Ty @k') prov) =>
204 (forall k'. ProvenanceKindOf (Var @k') prov) =>
209 Either (ErrorUnify prov) (Subst prov ws)
211 case va `lookupSubst` sub of
212 Just a -> unifyType sub b a
214 case sub `subst` b of
215 TyVar{tyVar = vb} | Just HRefl <- va `eqTy` vb -> Right sub
217 | va `varOccursIn` b' -> Left $ ErrorUnifyVarLoop (indexVar va) (TyVT b')
218 | HRefl :: a :~~: b <- unsafeCoerce HRefl ->
219 Right $ insertSubst va b' mempty <> sub
225 Either (ErrorUnify prov) (Subst prov ws)
226 goZip sub [] [] = Right sub
227 goZip sub (TyT a : as) (TyT b : bs) =
229 Nothing -> Left $ ErrorUnifyKind (TyT aK) (TyT bK) (TyVT a) (TyVT b)
230 Just HRefl -> unifyType sub a b >>= \sub' -> goZip sub' as bs
234 goZip _vs _a _b = Prelude.error "[BUG] unifyType: kinds mismatch"