module Top.Types.Synonym where
import Top.Types.Primitive
import Top.Types.Substitution hiding (lookupInt)
import Utils (internalError)
import Data.Maybe
import Data.Graph (scc, buildG)
import Data.Tree (flatten)
import qualified Data.Map as M
type TypeSynonyms = M.Map String (Int, Tps -> Tp)
type TypeSynonymOrdering = M.Map String Int
type OrderedTypeSynonyms = (TypeSynonymOrdering, TypeSynonyms)
noOrderedTypeSynonyms :: OrderedTypeSynonyms
noOrderedTypeSynonyms = (M.empty, M.empty)
stringAsTypeSynonym :: OrderedTypeSynonyms
stringAsTypeSynonym = (M.singleton "String" 0, M.singleton "String" (0, \_ -> listType charType))
getTypeSynonymOrdering :: TypeSynonyms -> (TypeSynonymOrdering, [[String]])
getTypeSynonymOrdering synonyms =
let
(nameTable, intTable) = let keys = M.keys synonyms
in ( M.fromList (zip keys [0..])
, M.fromList (zip [0..] keys)
)
err = internalError "Top.Types.Synonyms" "getTypeSynonymOrdering" "error in lookup table"
lookupName n = fromMaybe err (M.lookup n nameTable)
lookupInt i = fromMaybe err (M.lookup i intTable)
edges = let op s1 (arity, function) es =
let i1 = lookupName s1
cs = constantsInType (function (map TVar [0 .. arity 1]))
add s2 = case M.lookup s2 nameTable of
Just i2 -> (:) (i2,i1)
Nothing -> id
in foldr add es cs
in M.foldrWithKey op [] synonyms
graph = buildG (0, M.size synonyms 1) edges
list = map flatten (scc graph)
(ordering, recursive, _) =
let op ints (os, rs, counter) =
case ints of
[int] | (int, int) `notElem` edges
-> (M.insert (lookupInt int) counter os, rs, counter + 1)
_ -> (os, map lookupInt ints : rs, counter)
in foldr op (M.empty, [], 0) list
in
(ordering, recursive)
isPhantomTypeSynonym :: OrderedTypeSynonyms -> String -> Bool
isPhantomTypeSynonym (_, xs) s =
case M.lookup s xs of
Nothing -> False
Just (i, f) ->
let is = take i [0..]
tp = f (map TVar is)
free = ftv tp
in any (`notElem` free) is
expandType :: TypeSynonyms -> Tp -> Tp
expandType synonyms tp =
let (x,xs) = leftSpine (expandTypeConstructor synonyms tp)
in foldl TApp x (map (expandType synonyms) xs)
expandTypeConstructor :: TypeSynonyms -> Tp -> Tp
expandTypeConstructor synonyms tp =
maybe tp (expandTypeConstructor synonyms) (expandTypeConstructorOneStep synonyms tp)
expandToplevelTC :: OrderedTypeSynonyms -> Tp -> Maybe Tp
expandToplevelTC (_, synonyms) =
fmap (expandTypeConstructor synonyms) . expandTypeConstructorOneStep synonyms
expandTypeConstructorOneStep :: TypeSynonyms -> Tp -> Maybe Tp
expandTypeConstructorOneStep synonyms tp =
case leftSpine tp of
(TCon s, tps) -> case M.lookup s synonyms of
Just (i, f) | i == length tps -> Just (f tps)
| otherwise -> internalError "Top.Types.Synonyms"
"expandTypeConstructorOneStep"
"invalid arity of type synonym"
Nothing -> Nothing
_ -> Nothing
expandOneStepOrdered :: OrderedTypeSynonyms -> (Tp, Tp) -> Maybe (Tp, Tp)
expandOneStepOrdered (ordering, synonyms) (t1,t2) =
let f tp = case fst (leftSpine tp) of
TCon s -> M.lookup s ordering
_ -> Nothing
expand tp = fromMaybe err (expandTypeConstructorOneStep synonyms tp)
err = internalError "Top.Types.Synonyms" "expandOneStep" "invalid set of OrderedTypeSynonyms"
in case (f t1, f t2) of
(Just i1, Just i2) | i1 <= i2 -> Just (expand t1, t2)
| otherwise -> Just (t1, expand t2)
(Just _ , Nothing) -> Just (expand t1, t2)
(Nothing, Just _ ) -> Just (t1, expand t2)
_ -> Nothing