Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Implement Typeable
  • Loading branch information
TheMatten committed May 29, 2021
commit 1e470e0be0522683978bb5b67a909a31bbcc1d0b
11 changes: 11 additions & 0 deletions src/Language/PureScript/Constants/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,17 @@ pattern DataSymbol = ModuleName "Data.Symbol"
pattern IsSymbol :: Qualified (ProperName 'ClassName)
pattern IsSymbol = Qualified (Just DataSymbol) (ProperName "IsSymbol")

-- Type.Rep

pattern TypeRep :: ModuleName
pattern TypeRep = ModuleName "Type.Rep"

pattern Typeable :: Qualified (ProperName 'ClassName)
pattern Typeable = Qualified (Just TypeRep) (ProperName "Typeable")

typeRep :: forall a. (IsString a) => a
typeRep = "typeRep"

prelude :: forall a. (IsString a) => a
prelude = "Prelude"

Expand Down
43 changes: 41 additions & 2 deletions src/Language/PureScript/TypeChecker/Entailment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ import Control.Monad.Writer
import Data.Foldable (for_, fold, toList)
import Data.Function (on)
import Data.Functor (($>))
import Data.List (findIndices, minimumBy, groupBy, nubBy, sortOn)
import Data.List (findIndices, foldl', minimumBy, groupBy, nubBy, sortOn)
import Data.Maybe (fromMaybe, listToMaybe, mapMaybe)
import qualified Data.Map as M
import qualified Data.Set as S
import Data.String (fromString)
import Data.Traversable (for)
import Data.Text (Text, stripPrefix, stripSuffix)
import qualified Data.Text as T
import qualified Data.List.NonEmpty as NEL
import GHC.Fingerprint (Fingerprint, fingerprintString)

import Language.PureScript.AST
import Language.PureScript.Crash
Expand All @@ -42,7 +44,7 @@ import Language.PureScript.TypeChecker.Unify
import Language.PureScript.TypeClassDictionaries
import Language.PureScript.Types
import Language.PureScript.Label (Label(..))
import Language.PureScript.PSString (PSString, mkString, decodeString)
import Language.PureScript.PSString (PSString, mkString, decodeString, decodeStringEither)
import qualified Language.PureScript.Constants.Prelude as C
import qualified Language.PureScript.Constants.Prim as C

Expand All @@ -54,6 +56,7 @@ data Evidence
-- | Computed instances
| WarnInstance SourceType -- ^ Warn type class with a user-defined warning message
| IsSymbolInstance PSString -- ^ The IsSymbol type class for a given Symbol literal
| TypeableInstance Fingerprint -- ^ The Typeable type class for a given type
| EmptyClassInstance -- ^ For any solved type class with no members
deriving (Show, Eq)

Expand Down Expand Up @@ -176,6 +179,7 @@ entails SolverOptions{..} constraint context hints =
-- This allows us to defer a warning by propagating the constraint.
findDicts ctx cn Nothing ++ [TypeClassDictionaryInScope Nothing 0 (WarnInstance msg) [] C.Warn [] [] [msg] Nothing]
forClassName _ _ C.IsSymbol _ args | Just dicts <- solveIsSymbol args = dicts
forClassName _ _ C.Typeable kinds args | Just dicts <- solveTypeable kinds args = dicts
forClassName _ _ C.SymbolCompare _ args | Just dicts <- solveSymbolCompare args = dicts
forClassName _ _ C.SymbolAppend _ args | Just dicts <- solveSymbolAppend args = dicts
forClassName _ _ C.SymbolCons _ args | Just dicts <- solveSymbolCons args = dicts
Expand Down Expand Up @@ -379,6 +383,9 @@ entails SolverOptions{..} constraint context hints =
mkDictionary (IsSymbolInstance sym) _ =
let fields = [ ("reflectSymbol", Abs (VarBinder nullSourceSpan UnusedIdent) (Literal nullSourceSpan (StringLiteral sym))) ] in
return $ TypeClassDictionaryConstructorApp C.IsSymbol (Literal nullSourceSpan (ObjectLiteral fields))
mkDictionary (TypeableInstance fp) _ =
let fields = [ (C.typeRep, Literal nullSourceSpan $ StringLiteral $ fromString $ show fp) ] in
return $ TypeClassDictionaryConstructorApp C.Typeable (Literal nullSourceSpan (ObjectLiteral fields))

unknownsInAllCoveringSets :: [SourceType] -> S.Set (S.Set Int) -> Bool
unknownsInAllCoveringSets tyArgs = all (\s -> any (`S.member` s) unkIndices)
Expand Down Expand Up @@ -416,6 +423,38 @@ entails SolverOptions{..} constraint context hints =
solveIsSymbol [TypeLevelString ann sym] = Just [TypeClassDictionaryInScope Nothing 0 (IsSymbolInstance sym) [] C.IsSymbol [] [] [TypeLevelString ann sym] Nothing]
solveIsSymbol _ = Nothing

solveTypeable :: [SourceType] -> [SourceType] -> Maybe [TypeClassDict]
solveTypeable [kind] [type_]
| Just tS <- normalizedTypeS type_ = Just
[TypeClassDictionaryInScope Nothing 0 (TypeableInstance $ fingerprintString $ tS "") [] C.Typeable [] [kind] [type_] Nothing]
where
normalizedTypeS t = case rowToSortedList t of
([], t') -> case t' of
TypeLevelString _ s -> Just $ shows s
TypeConstructor _ (Qualified mn (ProperName cn)) -> Just $
maybe id ((. showString ".") . showString . T.unpack . runModuleName) mn . showString (T.unpack cn)
TypeApp _ t1 t2 -> do
t1S <- normalizedTypeS t1
t2S <- normalizedTypeS t2
Just $ showString "(" . t1S . showString ")(" . t2S . showString ")"
KindApp _ t1 t2 -> do
t1S <- normalizedTypeS t1
t2S <- normalizedTypeS t2
Just $ showString "(" . t1S . showString ")@(" . t2S . showString ")"
REmpty _ -> Just $ showString "()"
_ -> Nothing
(row, isREmpty -> True) -> do
rowS <- normalizedRowS row
Just $ showString "(" . rowS . showString ")"
_ -> Nothing
normalizedRowS = foldl' go (Just id) where
go s (RowListItem _ (Label n) t) = do
s' <- s
lbl <- traverse (either (\_ -> Nothing) Just) $ decodeStringEither n
tS <- normalizedTypeS t
Just $ s' . showString lbl . showString "::" . tS . showString ","
solveTypeable _ _ = Nothing

solveSymbolCompare :: [SourceType] -> Maybe [TypeClassDict]
solveSymbolCompare [arg0@(TypeLevelString _ lhs), arg1@(TypeLevelString _ rhs), _] =
let ordering = case compare lhs rhs of
Expand Down