blob: 63d11eb6794255b1844b57d6b4f143f0d9e3d878 [file] [log] [blame] [edit]
-- |
-- Module : Minigent.TC.Simplify
-- Copyright : (c) Data61 2018-2019
-- Commonwealth Science and Research Organisation (CSIRO)
-- ABN 41 687 119 230
-- License : BSD3
--
-- The simplify phase of the solver.
--
-- May be used qualified or unqualified.
module Minigent.TC.Simplify 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 Control.Monad
import Data.Maybe (mapMaybe)
import qualified Data.Set as S
import qualified Data.Map as M
import Data.Foldable (toList)
import Minigent.Syntax.PrettyPrint
import Debug.Trace
-- | Rewrite a set of constraints, removing all trivially satisfiable constraints
-- and breaking down large constraints into smaller ones.
simplify :: [Constraint] -> Rewrite.Rewrite [Constraint]
simplify axs = Rewrite.pickOne $ \c -> -- trace ("About to simpliy:\n" ++ debugPrettyConstraints [c]) $
case c of
c | c `elem` axs -> Just []
Sat -> Just []
c1 :&: c2 -> Just [c1,c2]
Drop (PrimType _) -> Just []
Share (PrimType _) -> Just []
Escape (PrimType _) -> Just []
Drop (Function _ _) -> Just []
Share (Function _ _) -> Just []
Escape (Function _ _) -> Just []
Drop (TypeVarBang _) -> Just []
Share (TypeVarBang _) -> Just []
Drop (RecParBang _ _) -> Just []
Share (RecParBang _ _) -> Just []
Share (Variant es) -> guard (rowVar es == Nothing)
>> Just (map Share (Row.untakenTypes es))
Drop (Variant es) -> guard (rowVar es == Nothing)
>> Just (map Drop (Row.untakenTypes es))
Escape (Variant es) -> guard (rowVar es == Nothing)
>> Just (map Escape (Row.untakenTypes es))
Share (AbsType n s ts) -> guard (s == ReadOnly || s == Unboxed)
>> Just (map Share ts)
Drop (AbsType n s ts) -> guard (s == ReadOnly || s == Unboxed)
>> Just (map Drop ts)
Escape (AbsType n s ts) -> guard (s == Writable || s == Unboxed)
>> Just (map Escape ts)
Share (Record n es s) -> guard (s == ReadOnly || s == Unboxed)
>> guard (rowVar es == Nothing)
>> Just (map Share (Row.untakenTypes es))
Drop (Record n es s) -> guard (s == ReadOnly || s == Unboxed)
>> guard (rowVar es == Nothing)
>> Just (map Drop (Row.untakenTypes es))
Escape (Record n es s) -> guard (s == Writable || s == Unboxed)
>> guard (rowVar es == Nothing)
>> Just (map Escape (Row.untakenTypes es))
Exhausted (Variant es) -> guard (null (Row.untakenTypes es) && rowVar es == Nothing)
>> Just []
i :<=: PrimType t -> guard (fits i t) >> Just []
Function t1 t2 :< Function r1 r2 -> Just [r1 :< t1, t2 :< r2]
Function t1 t2 :=: Function r1 r2 -> Just [r1 :=: t1, t2 :=: r2]
Variant r1 :< Variant r2 ->
if Row.null r1 && Row.null r2 then Just []
else if Row.null r1 && null (Row.entries r2)
|| Row.null r2 && null (Row.entries r1)
then Just [Variant r1 :=: Variant r2]
else do
let commons = Row.common r1 r2
(ls, rs) = unzip commons
guard (not (null commons))
guard (untakenLabels ls `S.isSubsetOf` untakenLabels rs)
let (r1',r2') = Row.withoutCommon r1 r2
cs = map (\(Entry _ t _, Entry _ t' _) -> t :< t') commons
c = Variant r1' :< Variant r2'
Just (c:cs)
Record n1 r1 s1 :< Record n2 r2 s2 ->
if Row.null r1 && Row.null r2 && s1 == s2 && n1 == n2 then Just []
else if Row.null r1 && null (Row.entries r2)
|| Row.null r2 && null (Row.entries r1)
then Just [Record n1 r1 s1 :=: Record n2 r2 s2]
else do
let commons = Row.common r1 r2
(ls, rs) = unzip commons
guard (not (null commons))
guard (untakenLabels rs `S.isSubsetOf` untakenLabels ls)
let (r1',r2') = Row.withoutCommon r1 r2
cs = map (\(Entry _ t _, Entry _ t' _) -> t :< t') commons
ds = map Drop (Row.typesFor (untakenLabels ls S.\\ untakenLabels rs) r1)
c = Record n1 r1' s1 :< Record n2 r2' s2
Just (c:cs ++ ds)
{-
- Recursive Parameters:
- If we are reasoning about two recursive parameters, check if their context references
- are equal. We *do not* unroll here, and if we arrive at the same position where the contexts
- are both `Nothing', then the RecPars are truly equal.
-
- N.B. recursive parameters need only be *alpha* equivalent, hence we do not check if the names are equal
-}
RecPar n (Just ctxt) :< RecPar n' (Just ctxt') -> Just [(ctxt M.! n) :< (ctxt M.! n')]
RecPar n (Just ctxt) :=: RecPar n' (Just ctxt') -> Just [(ctxt M.! n) :=: (ctxt M.! n')]
RecParBang n (Just ctxt) :< RecParBang n' (Just ctxt') -> Just [(ctxt M.! n) :< (ctxt M.! n')]
RecParBang n (Just ctxt) :=: RecParBang n' (Just ctxt') -> Just [(ctxt M.! n) :=: (ctxt M.! n')]
RecPar n Nothing :< RecPar n' Nothing -> Just []
RecPar n Nothing :=: RecPar n' Nothing -> Just []
RecParBang n Nothing :< RecParBang n' Nothing -> Just []
RecParBang n Nothing :=: RecParBang n' Nothing -> Just []
-- We need this here as otherwise it triggers the cases below
RecParBang n ctxt :< RecPar n' ctxt' -> Nothing
RecPar n ctxt :< RecParBang n' ctxt' -> Nothing
RecParBang n ctxt :=: RecPar n' ctxt' -> Nothing
RecPar n ctxt :=: RecParBang n' ctxt' -> Nothing
{-
- otherwise:
- If we are reasoning about a recursive parameter and a type, unroll the parameter
- and reason about the type and the unrolled parameter
-}
RecPar n ctxt :< t@Record{} -> Just [unroll n ctxt :< t]
t@Record{} :< RecPar n ctxt -> Just [t :< unroll n ctxt]
RecPar n ctxt :=: t@Record{} -> Just [unroll n ctxt :=: t]
t@Record{} :=: RecPar n ctxt -> Just [t :=: unroll n ctxt]
RecParBang n ctxt :< t@Record{} -> Just [Bang (unroll n ctxt) :< t]
t@Record{} :< RecParBang n ctxt -> Just [t :< Bang (unroll n ctxt)]
RecParBang n ctxt :=: t@Record{} -> Just [Bang (unroll n ctxt) :=: t]
t@Record{} :=: RecParBang n ctxt -> Just [t :=: Bang (unroll n ctxt)]
t :< t' -> guard (unorderedType t || unorderedType t') >> Just [t :=: t']
AbsType n s ts :=: AbsType n' s' ts' -> guard (n == n' && s == s') >> Just (zipWith (:=:) ts ts')
Variant r1 :=: Variant r2 ->
if Row.null r1 && Row.null r2 then Just []
else if Row.justVar r1 && Row.justVar r2 && r1 == r2
then Just [Solved (Variant r1)]
else do
let commons = Row.common r1 r2
(ls, rs) = unzip commons
guard (not (null commons))
guard (untakenLabels ls == untakenLabels rs)
let (r1',r2') = Row.withoutCommon r1 r2
cs = map (\(Entry _ t _, Entry _ t' _) -> t :=: t') commons
c = Variant r1' :=: Variant r2'
Just (c:cs)
Record rp1 r1 s1 :=: Record rp2 r2 s2 ->
if Row.null r1 && Row.null r2 && s1 == s2 && sameRecursive rp1 rp2 then Just []
else if Row.justVar r1 && Row.justVar r2 && s1 == s2 && r1 == r2 && sameRecursive rp1 rp2
then Just [Solved (Record rp1 r1 s1)]
else do
let commons = Row.common r1 r2
(ls, rs) = unzip commons
guard (not (null commons))
guard (untakenLabels rs == untakenLabels ls)
let (r1',r2') = Row.withoutCommon r1 r2
cs = map (\(Entry _ t _, Entry _ t' _) -> t :=: t') commons
c = Record rp1 r1' s1 :=: Record rp2 r2' s2
Just (c:cs)
t :=: t' -> guard (t == t') >> if typeUVs t == [] then Just []
else Just [Solved t]
Solved t -> guard (typeUVs t == []) >> Just []
-- If an unboxed record has no recursive parameter, sat
UnboxedNoRecurse None Unboxed -> Just []
-- If a boxed record, sat
UnboxedNoRecurse _ c | (c == ReadOnly || c == Writable) -> Just []
_ -> Nothing
where
untakenLabels :: [Entry] -> S.Set FieldName
untakenLabels = S.fromList . mapMaybe (\(Entry l _ t) -> guard (not t) >> pure l)