blob: 2243c2ecaed95c1a1f1d3bdc552cd509ad307a89 [file] [log] [blame] [edit]
-- |
-- Module : Minigent.TC.Unify
-- Copyright : (c) Data61 2018-2019
-- Commonwealth Science and Research Organisation (CSIRO)
-- ABN 41 687 119 230
-- License : BSD3
--
-- The unify phase of the constraint solver.
--
-- May be used qualified or unqualified.
{-# OPTIONS_GHC -Werror -Wall #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Minigent.TC.Unify
( -- * Unify Phase
unify
) where
import Minigent.Syntax
import Minigent.Syntax.Utils
import qualified Minigent.Syntax.Utils.Row as Row
import qualified Minigent.Syntax.Utils.Rewrite as Rewrite
import Minigent.TC.Assign
import Minigent.Fresh
import Control.Monad.Writer
import Control.Monad.Trans.Maybe (MaybeT(..))
-- | The unify phase, which seeks out equality constraints to solve via substitution.
unify :: (MonadFresh VarName m, MonadWriter [Assign] m) => Rewrite.Rewrite' m [Constraint]
unify = Rewrite.rewrite' $ \cs -> MaybeT $ do
substs <- concat <$> traverse assignOf cs
tell substs
if null substs
then return Nothing
else let (m1,m2,m3,m4) = substsToMaps substs
cs' = map (substConstraint' m1 m2 m3 m4) cs
in if cs' == cs
then return Nothing
else return $ Just cs'
assignOf :: (MonadFresh VarName m, MonadWriter [Assign] m) => Constraint -> m [Assign]
assignOf (UnifVar a :=: tau) | rigid tau && (a `notOccurs` tau) = pure [TyAssign a tau]
assignOf (tau :=: UnifVar a) | rigid tau && (a `notOccurs` tau) = pure [TyAssign a tau]
assignOf (Record _ _ (UnknownSigil v) :=: Record _ _ s)
| s `elem` [ReadOnly, Unboxed, Writable]
= pure [ SigilAssign v s ]
assignOf (Record _ _ s :=: Record _ _ (UnknownSigil v))
| s `elem` [ReadOnly, Unboxed, Writable]
= pure [ SigilAssign v s ]
assignOf (Record _ _ (UnknownSigil v) :< Record _ _ s)
| s `elem` [ReadOnly, Unboxed, Writable]
= pure [ SigilAssign v s ]
assignOf (Record _ _ s :< Record _ _ (UnknownSigil v))
| s `elem` [ReadOnly, Unboxed, Writable]
= pure [ SigilAssign v s ]
-- N.B. we know from the previous phase that common alternatives have been factored out.
assignOf (Variant r1 :=: Variant r2)
| rowVar r1 /= rowVar r2
, [] <- Row.common r1 r2
= case (rowVar r1, rowVar r2) of
(Just x, Nothing) -> pure [RowAssign x r2]
(Nothing, Just x) -> pure [RowAssign x r1]
(Just x , Just y) -> do v <- fresh
pure [ RowAssign x (r2 { rowVar = Just v })
, RowAssign y (r1 { rowVar = Just v })
]
_ -> pure []
-- N.B. we know from the previous phase that common fields have been factored out.
assignOf (Record _ r1 s1 :=: Record _ r2 s2)
| rowVar r1 /= rowVar r2, s1 == s2
, [] <- Row.common r1 r2
= case (rowVar r1, rowVar r2) of
(Just x, Nothing) -> pure [RowAssign x r2]
(Nothing, Just x) -> pure [RowAssign x r1]
(Just x , Just y) -> do v <- fresh
pure [ RowAssign x (r2 { rowVar = Just v })
, RowAssign y (r1 { rowVar = Just v })
]
_ -> pure []
assignOf (Record n1 _ _ :=: Record n2 _ _)
= case (n1,n2) of
(Rec _, UnknownParameter x) -> pure [RecParAssign x n1]
(UnknownParameter x, Rec _) -> pure [RecParAssign x n2]
(UnknownParameter x, None) -> pure [RecParAssign x None]
(None, UnknownParameter x) -> pure [RecParAssign x None]
_ -> pure []
assignOf (Record rp1 _ _ :< Record rp2 _ _)
= case (rp1,rp2) of
(Rec _, UnknownParameter x) -> pure [RecParAssign x rp1]
(UnknownParameter x, Rec _) -> pure [RecParAssign x rp2]
(UnknownParameter x, None) -> pure [RecParAssign x None]
(None, UnknownParameter x) -> pure [RecParAssign x None]
_ -> pure []
-- If it is discovered that a sigil is unboxed, we can assign it's
-- unknown parameter to None
assignOf (UnboxedNoRecurse (UnknownParameter x) Unboxed)
= pure [RecParAssign x None]
assignOf _ = pure []
notOccurs :: VarName -> Type -> Bool
notOccurs a tau = a `notElem` typeUVs tau