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 Control.Monad.Classes as MC (MonadExcept, throw)
11 import Control.Monad.Classes.Run as MC ()
12 import Data.Bool (otherwise)
13 import Data.Eq (Eq (..))
14 import Data.Function (id, ($))
15 import Data.Functor ((<$>))
16 import Data.Map.Strict (Map)
17 import Data.Map.Strict qualified as Map
18 import Data.Maybe (Maybe (..))
19 import Data.Monoid (Monoid (..))
20 import Data.Semigroup (Semigroup (..))
21 import Text.Show (Show)
22 import Type.Reflection ((:~~:) (..))
23 import Unsafe.Coerce (unsafeCoerce)
24 import Prelude qualified
26 -- import Symantic.Grammar
27 import Symantic.Typer.Variable ()
29 -- import Symantic.Typer.Kind
31 import Symantic.Parser.Error (ErrorInj (..))
32 import Symantic.Parser.Source (Source, SourceInj)
33 import Symantic.Typer.Eq (EqTy (eqTy))
34 import Symantic.Typer.Type (
38 Ty (TyApp, TyConst, TyVar, tyConst, tyVar),
49 -- import Symantic.Typer.Show ()
53 -- | /Type variable substitution/.
55 -- WARNING: a 'Subst' MUST be without loops, and fully expanded.
57 = Subst (Map IndexVar (VT meta vs))
59 deriving instance (Show meta, Monoid meta) => Show (Subst meta vs)
60 instance Monoid meta => Semigroup (Subst meta vs) where
62 instance Monoid meta => Monoid (Subst meta vs) where
63 mempty = Subst Map.empty
66 -- | Unify two 'Subst's.
68 -- NOTE: the union is left-biased: in case of duplicate 'Var's,
69 -- it keeps the one from the first 'Subst' given.
71 -- NOTE: the first 'Subst' given is applied to the second (with 'subst'),
72 -- this way each 'Var' directly maps to an expanded 'Type',
73 -- so that, when using the resulting 'Subst',
74 -- there is no need to apply it multiple times
75 -- until there is no more substitution to be done.
76 unionSubst :: Subst meta vs -> Subst meta vs -> Subst meta vs
77 unionSubst sx@(Subst x) (Subst y) = Subst $ x `Map.union` ((\(VT v r) -> VT v $ subst sx r) Data.Functor.<$> y)
81 -- | A 'Var' and a 'Type' existentialized over their type index.
82 data VT meta vs = forall t. VT (Var meta vs t) (Ty meta vs t)
84 deriving instance (Show meta, Monoid meta) => Show (VT meta vs)
86 insertSubst :: Monoid meta => Var meta vs v -> Ty meta vs v -> Subst meta vs -> Subst meta vs
87 insertSubst v t (Subst s) = Subst $ Map.insert (indexVar v) (VT v t) s
89 lookupSubst :: Monoid meta => Var meta vs v -> Subst meta vs -> Maybe (Ty meta vs v)
90 lookupSubst v (Subst s)
91 | Just (VT v' t) <- Map.lookup (indexVar v) s
92 , Just Type.Reflection.HRefl <- v `eqTy` v' =
94 lookupSubst _v _m = Nothing
96 -- * Class 'Substable'
97 class Substable t where
98 -- | Like 'substVar', but without the /occurence check/.
100 Var meta vs v -> Ty meta vs v -> t meta vs a -> t meta vs a
102 -- | Substitute all the 'Var's which have a match in given 'Subst'.
104 Subst meta vs -> t meta vs a -> t meta vs a
105 instance Substable Ty where
106 substVarUnsafe _v _r t@TyConst{} = t
107 substVarUnsafe v r (TyApp f a) =
109 (substVarUnsafe v r f)
110 (substVarUnsafe v r a)
111 substVarUnsafe v r t@TyVar{tyVar = tv} =
113 Just Type.Reflection.HRefl -> r
116 -- substVarUnsafe v r (TyFam meta len fam as) =
117 -- TyFam meta len fam $ substVarUnsafe v r as
119 subst _s t@TyConst{} = t
120 subst s (TyApp f a) = TyApp (subst s f) (subst s a)
121 subst (Subst s) t@TyVar{tyVar = tv} =
122 case Map.lookup (indexVar tv) s of
126 Nothing -> Prelude.error "[BUG] subst: kind mismatch"
127 Just Type.Reflection.HRefl -> r
129 -- subst s (TyFam meta len fam as) = TyFam meta len fam $ subst s as
130 instance Substable (Tys as) where
131 substVarUnsafe _v _r TysZ = TysZ
132 substVarUnsafe v r (TysS t ts) =
134 `TysS` substVarUnsafe v r ts
136 subst s (TysS t ts) = subst s t `TysS` subst s ts
138 -- | Substitute the given 'Var' by the given 'Type',
139 -- returning 'Nothing' if this 'Type' contains
140 -- the 'Var' (occurence check).
150 then Nothing -- NOTE: occurence check
151 else Just $ substVarUnsafe v r t
153 -- ** Type 'ErrorUnify'
155 -- | Reasons why two 'Type's cannot be unified.
157 = -- | /occurence check/: a 'Var' is unified with a 'Type'
158 -- which contains this same 'Var'.
159 ErrorUnifyVarLoop IndexVar (TyVT meta)
160 | -- | Two 'TyConst's should be the same, but are different.
161 ErrorUnifyConst (TyVT meta) (TyVT meta)
162 | -- | Two 'Kind's should be the same, but are different.
163 ErrorUnifyKind (KindK meta) (KindK meta)
164 | -- | Cannot unify those two 'Type's.
165 ErrorUnifyType (TyVT meta) (TyVT meta)
167 deriving instance Monoid meta => Eq (ErrorUnify meta)
168 deriving instance (Show meta, Monoid meta) => Show (ErrorUnify meta)
170 instance ErrorInj (ErrorUnify meta) (ErrorUnify meta) where
173 data SourceTypeArg meta
174 = SourceTypeArg (TyVT meta)
176 -- | Return the left spine of a 'Ty':
177 -- the root 'Ty' and its 'Ty' parameters,
178 -- from the left to the right.
181 -- MC.MonadWriter (SourceTypeArg meta) (Sourced meta) =>
183 SourceInj (TyVT meta) meta =>
185 (TyT meta vs, [TyT meta vs])
188 go :: forall kx (x :: kx). [TyT meta vs] -> Ty meta vs x -> (TyT meta vs, [TyT meta vs])
189 -- Skip the constraint @q@.
190 go ctx (TyApp (TyApp (TyConst{tyConst = c}) _q) t)
191 | Just Type.Reflection.HRefl <- proj_ConstKi @_ @(#>) c =
193 -- Add a type to the spine.
194 go ctx (TyApp f a) = go (TyT a {-(SourceTypeArg (TyVT ty)-} : ctx) f
196 go ctx t = (TyT t {-SourceTypeArg (TyVT ty)-}, ctx)
200 :: Ty meta ctx ss cs (t::k)
201 -> (forall kx (x::kx) xs. Ty meta ctx ss cs x -> Tys meta ctx ss cs xs -> ret)
205 go :: Tys meta ctx ss cs hs
206 -> Ty meta ctx ss cs (t::k)
207 -> (forall kx (x::kx) xs. Ty meta ctx ss cs x -> Tys meta ctx ss cs xs -> ret)
209 go ctx (TyApp _src f a) k = go (a `TysS` ctx) f k
210 go ctx (Term x _te) k = go ctx x k
211 go ctx (TyAny x) k = go ctx x k
215 -- | Return the /most general unification/ of two 'Type's, when it exists.
217 forall ki (x :: ki) (y :: ki) vs meta m.
218 SourceInj (TyVT meta) meta =>
219 -- ErrorInj (Con_Kind meta) (ErrorUnify meta) =>
220 MC.MonadExcept (ErrorUnify meta) m =>
222 Ty meta vs (x :: ki) ->
223 Ty meta vs (y :: ki) ->
227 in case (spineTy x, spineTy y) of
228 ((TyT xRootTy, px), (TyT yRootTy, py)) ->
229 case (xRootTy, yRootTy) of
230 (TyVar{tyVar = vx}, _) | Just Type.Reflection.HRefl <- k `eqTy` kindOf vx -> goVar vs vx y
231 (_, TyVar{tyVar = vy}) | Just Type.Reflection.HRefl <- k `eqTy` kindOf vy -> goVar vs vy x
232 (TyConst{tyConst = cx}, TyConst{tyConst = cy})
233 | Just Type.Reflection.HRefl <- cx `eqTy` cy -> goZip vs px py
234 | otherwise -> MC.throw $ ErrorUnifyConst (TyVT xRootTy) (TyVT yRootTy)
237 (TyApp fx ax, TyApp fy ay) -> goZip vs [TyT fx, TyT ax] [TyT fy, TyT ay]
238 _ -> MC.throw $ ErrorUnifyType (TyVT x) (TyVT y)
241 forall k (a :: k) (b :: k) vs'.
247 case va `lookupSubst` vs' of
248 Just a -> unifyType vs' b a
250 case vs' `subst` b of
251 TyVar{tyVar = vb} | Just Type.Reflection.HRefl <- va `eqTy` vb -> return vs'
253 | va `varOccursIn` b' -> MC.throw $ ErrorUnifyVarLoop (indexVar va) (TyVT b')
254 | Type.Reflection.HRefl :: a Type.Reflection.:~~: b <- unsafeCoerce Type.Reflection.HRefl ->
255 return $ insertSubst va b' mempty <> vs'
262 goZip vs' [] [] = return vs'
263 goZip vs' (TyT a : as) (TyT b : bs) =
266 in case xK `eqTy` yK of
267 Nothing -> MC.throw $ ErrorUnifyKind (TyT xK) (TyT yK)
268 Just Type.Reflection.HRefl -> unifyType vs' a b >>= \vs'' -> goZip vs'' as bs
269 goZip _vs _a _b = Prelude.error "[BUG] unifyType: kinds mismatch"