1
1
mirror of https://github.com/github/semantic.git synced 2025-01-04 13:34:31 +03:00

add a type map to type checker and prune types in unification

This commit is contained in:
Charlie Somerville 2018-07-04 15:48:41 +10:00
parent 1bbca41294
commit bebb6ebe6b
2 changed files with 69 additions and 19 deletions

View File

@ -1,14 +1,15 @@
{-# LANGUAGE GADTs, RankNTypes, TypeFamilies, TypeOperators, UndecidableInstances #-}
{-# LANGUAGE GADTs, RankNTypes, TypeFamilies, TypeOperators, UndecidableInstances, LambdaCase #-}
module Data.Abstract.Type
( Type (..)
, TypeError (..)
, runTypeError
, runTypes
, unify
) where
import Control.Abstract
import Data.Abstract.Environment as Env
import Data.Semigroup.Foldable (foldMap1)
import qualified Data.Map as Map
import Prologue hiding (TypeError)
type TName = Int
@ -67,28 +68,75 @@ instance Eq1 TypeError where liftEq _ (UnificationError a1 b1) (Unificati
instance Ord1 TypeError where liftCompare _ (UnificationError a1 b1) (UnificationError a2 b2) = compare a1 a2 <> compare b1 b2
instance Show1 TypeError where liftShowsPrec _ _ = showsPrec
runTypeError :: Effectful m => m (Resumable TypeError ': effects) a -> m effects (Either (SomeExc TypeError) a)
runTypeError = runResumable
runTypeMap :: ( Effectful m
, Monad (m effects)
)
=> m (State TypeMap ': effects) a
-> m effects a
runTypeMap = runState emptyTypeMap >=> pure . fst
runTypes :: ( Effectful m
, Monad (m effects)
)
=> m (Resumable TypeError ': State TypeMap ': effects) a
-> m effects (Either (SomeExc TypeError) a)
runTypes = runTypeMap . runTypeError
newtype TypeMap = TypeMap { unTypeMap :: Map.Map TName Type }
emptyTypeMap :: TypeMap
emptyTypeMap = TypeMap Map.empty
modifyTypeMap :: ( Effectful m
, Member (State TypeMap) effects
)
=> (Map.Map TName Type -> Map.Map TName Type)
-> m effects ()
modifyTypeMap f = modify (TypeMap . f . unTypeMap)
prune :: ( Effectful m
, Monad (m effects)
, Member (State TypeMap) effects
)
=> Type
-> m effects Type
prune (Var id) = Map.lookup id . unTypeMap <$> get >>= \case
Just ty -> do
pruned <- prune ty
modifyTypeMap (Map.insert id pruned)
pure pruned
Nothing -> pure (Var id)
prune ty = pure ty
-- | Unify two 'Type's.
unify :: (Effectful m, Applicative (m effects), Member (Resumable TypeError) effects) => Type -> Type -> m effects Type
unify (a1 :-> b1) (a2 :-> b2) = (:->) <$> unify a1 a2 <*> unify b1 b2
unify a Null = pure a
unify Null b = pure b
-- FIXME: this should be constructing a substitution.
unify (Var _) b = pure b
unify a (Var _) = pure a
unify (Array t1) (Array t2) = Array <$> unify t1 t2
-- FIXME: unifying with sums should distribute nondeterministically.
-- FIXME: ordering shouldnt be significant for undiscriminated sums.
unify (a1 :+ b1) (a2 :+ b2) = (:+) <$> unify a1 a2 <*> unify b1 b2
unify (a1 :* b1) (a2 :* b2) = (:*) <$> unify a1 a2 <*> unify b1 b2
unify t1 t2
| t1 == t2 = pure t2
| otherwise = throwResumable (UnificationError t1 t2)
unify :: ( Effectful m
, Monad (m effects)
, Member (Resumable TypeError) effects
, Member (State TypeMap) effects
)
=> Type
-> Type
-> m effects Type
unify a b = do
a' <- prune a
b' <- prune b
case (a', b') of
(a1 :-> b1, a2 :-> b2) -> (:->) <$> unify a1 a2 <*> unify b1 b2
(a, Null) -> pure a
(Null, b) -> pure b
-- FIXME: this should be constructing a substitution.
(Var _, b) -> pure b
(a, Var _) -> pure a
(Array t1, Array t2) -> Array <$> unify t1 t2
-- FIXME: unifying with sums should distribute nondeterministically.
-- FIXME: ordering shouldnt be significant for undiscriminated sums.
(a1 :+ b1, a2 :+ b2) -> (:+) <$> unify a1 a2 <*> unify b1 b2
(a1 :* b1, a2 :* b2) -> (:*) <$> unify a1 a2 <*> unify b1 b2
(t1, t2) | t1 == t2 -> pure t2
_ -> throwResumable (UnificationError a b)
instance Ord address => ValueRoots address Type where
valueRoots _ = mempty
@ -115,6 +163,7 @@ instance ( Member (Allocator address Type) effects
, Member (Env address) effects
, Member Fresh effects
, Member (Resumable TypeError) effects
, Member (State TypeMap) effects
, Member (Return address) effects
)
=> AbstractFunction address Type effects where
@ -142,6 +191,7 @@ instance ( Member (Allocator address Type) effects
, Member Fresh effects
, Member NonDet effects
, Member (Resumable TypeError) effects
, Member (State TypeMap) effects
, Member (Return address) effects
)
=> AbstractValue address Type effects where

View File

@ -87,7 +87,7 @@ checking
. runEnvironmentError
. runEvalError
. runAddressError
. runTypeError
. runTypes
evalGoProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go
evalRubyProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby