Start on implementing abstract types/constants (module parameters)

This commit is contained in:
Iavor Diatchki 2017-09-15 16:05:16 -07:00
parent c05281d390
commit f3a3b1cbd0
16 changed files with 323 additions and 46 deletions

View File

@ -17,6 +17,7 @@ module Cryptol.ModuleSystem.Interface (
, IfaceTySyn, ifTySynName , IfaceTySyn, ifTySynName
, IfaceNewtype , IfaceNewtype
, IfaceDecl(..), mkIfaceDecl , IfaceDecl(..), mkIfaceDecl
, IfaceParams(..)
, genIface , genIface
, ifacePrimMap , ifacePrimMap
@ -37,9 +38,15 @@ import Prelude.Compat
-- | The resulting interface generated by a module that has been typechecked. -- | The resulting interface generated by a module that has been typechecked.
data Iface = Iface data Iface = Iface
{ ifModName :: !ModName { ifModName :: !ModName -- ^ Module name
, ifPublic :: IfaceDecls , ifPublic :: IfaceDecls -- ^ Exported definitions
, ifPrivate :: IfaceDecls , ifPrivate :: IfaceDecls -- ^ Private defintiions
, ifAbstract :: IfaceParams -- ^ Uninterpreted constants (aka module params)
} deriving (Show, Generic, NFData)
data IfaceParams = IfaceParams
{ ifAbsTypes :: Map.Map Name TParam -- ^ Uninterpreted types
, ifAbsFuns :: Map.Map Name IfaceDecl -- ^ Uninterpreted value constants
} deriving (Show, Generic, NFData) } deriving (Show, Generic, NFData)
data IfaceDecls = IfaceDecls data IfaceDecls = IfaceDecls
@ -69,12 +76,12 @@ ifTySynName = tsName
type IfaceNewtype = Newtype type IfaceNewtype = Newtype
data IfaceDecl = IfaceDecl data IfaceDecl = IfaceDecl
{ ifDeclName :: !Name { ifDeclName :: !Name -- ^ Name of thing
, ifDeclSig :: Schema , ifDeclSig :: Schema -- ^ Type
, ifDeclPragmas :: [Pragma] , ifDeclPragmas :: [Pragma] -- ^ Pragmas
, ifDeclInfix :: Bool , ifDeclInfix :: Bool -- ^ Is this an infix thing
, ifDeclFixity :: Maybe Fixity , ifDeclFixity :: Maybe Fixity -- ^ Fixity information
, ifDeclDoc :: Maybe String , ifDeclDoc :: Maybe String -- ^ Documentation
} deriving (Show, Generic, NFData) } deriving (Show, Generic, NFData)
mkIfaceDecl :: Decl -> IfaceDecl mkIfaceDecl :: Decl -> IfaceDecl
@ -91,23 +98,44 @@ mkIfaceDecl d = IfaceDecl
genIface :: Module -> Iface genIface :: Module -> Iface
genIface m = Iface genIface m = Iface
{ ifModName = mName m { ifModName = mName m
, ifPublic = IfaceDecls
{ ifTySyns = tsPub , ifPublic = IfaceDecls
, ifNewtypes = ntPub { ifTySyns = tsPub
, ifDecls = dPub , ifNewtypes = ntPub
, ifDecls = dPub
} }
, ifPrivate = IfaceDecls , ifPrivate = IfaceDecls
{ ifTySyns = tsPriv { ifTySyns = tsPriv
, ifNewtypes = ntPriv , ifNewtypes = ntPriv
, ifDecls = dPriv , ifDecls = dPriv
}
, ifAbstract = IfaceParams
{ ifAbsTypes = mAbsTypes m
, ifAbsFuns = valParams
} }
} }
where where
valParams = Map.mapWithKey xxxDecl (mAbsFuns m)
xxxDecl qn s = IfaceDecl
{ ifDeclName = qn
, ifDeclSig = s
, ifDeclPragmas = []
, ifDeclInfix = False
, ifDeclFixity = Nothing
, ifDeclDoc = Nothing
}
(tsPub,tsPriv) = (tsPub,tsPriv) =
Map.partitionWithKey (\ qn _ -> qn `isExportedType` mExports m ) (mTySyns m) Map.partitionWithKey (\ qn _ -> qn `isExportedType` mExports m )
(mTySyns m)
(ntPub,ntPriv) = (ntPub,ntPriv) =
Map.partitionWithKey (\ qn _ -> qn `isExportedType` mExports m ) (mNewtypes m) Map.partitionWithKey (\ qn _ -> qn `isExportedType` mExports m )
(mNewtypes m)
(dPub,dPriv) = (dPub,dPriv) =
Map.partitionWithKey (\ qn _ -> qn `isExportedBind` mExports m) Map.partitionWithKey (\ qn _ -> qn `isExportedBind` mExports m)

View File

@ -298,8 +298,22 @@ instance BindsNames (InModule (TopDecl PName)) where
case td of case td of
Decl d -> namingEnv (InModule ns (tlValue d)) Decl d -> namingEnv (InModule ns (tlValue d))
TDNewtype d -> namingEnv (InModule ns (tlValue d)) TDNewtype d -> namingEnv (InModule ns (tlValue d))
DAbstractType d -> namingEnv (InModule ns (tlValue d))
DAbstractFun d -> namingEnv (InModule ns (tlValue d))
Include _ -> mempty Include _ -> mempty
instance BindsNames (InModule (AbstractFun PName)) where
namingEnv (InModule ns AbstractFun { .. }) = BuildNamingEnv $
do let Located { .. } = afName
ntName <- liftSupply (mkDeclared ns (getIdent thing) Nothing srcRange)
return (singletonE thing ntName)
instance BindsNames (InModule (AbstractType PName)) where
namingEnv (InModule ns AbstractType { .. }) = BuildNamingEnv $
do let Located { .. } = atName
ntName <- liftSupply (mkDeclared ns (getIdent thing) Nothing srcRange)
return (singletonT thing ntName)
-- NOTE: we use the same name at the type and expression level, as there's only -- NOTE: we use the same name at the type and expression level, as there's only
-- ever one name introduced in the declaration. The names are only ever used in -- ever one name introduced in the declaration. The names are only ever used in
-- different namespaces, so there's no ambiguity. -- different namespaces, so there's no ambiguity.

View File

@ -360,6 +360,19 @@ instance Rename TopDecl where
Decl d -> Decl <$> traverse rename d Decl d -> Decl <$> traverse rename d
TDNewtype n -> TDNewtype <$> traverse rename n TDNewtype n -> TDNewtype <$> traverse rename n
Include n -> return (Include n) Include n -> return (Include n)
DAbstractFun f -> DAbstractFun <$> traverse rename f
DAbstractType f -> DAbstractType <$> traverse rename f
instance Rename AbstractType where
rename a =
do n' <- rnLocated renameType (atName a)
return a { atName = n' }
instance Rename AbstractFun where
rename a =
do n' <- rnLocated renameVar (afName a)
sig' <- renameSchema (afSchema a)
return a { afName = n', afSchema = snd sig' }
rnLocated :: (a -> RenameM b) -> Located a -> RenameM (Located b) rnLocated :: (a -> RenameM b) -> Located a -> RenameM (Located b)
rnLocated f loc = withLoc loc $ rnLocated f loc = withLoc loc $

View File

@ -56,6 +56,7 @@ import Paths_cryptol
'as' { Located $$ (Token (KW KW_as) _)} 'as' { Located $$ (Token (KW KW_as) _)}
'hiding' { Located $$ (Token (KW KW_hiding) _)} 'hiding' { Located $$ (Token (KW KW_hiding) _)}
'private' { Located $$ (Token (KW KW_private) _)} 'private' { Located $$ (Token (KW KW_private) _)}
'abstract' { Located $$ (Token (KW KW_abstract) _)}
'property' { Located $$ (Token (KW KW_property) _)} 'property' { Located $$ (Token (KW KW_property) _)}
'infix' { Located $$ (Token (KW KW_infix) _)} 'infix' { Located $$ (Token (KW KW_infix) _)}
'infixl' { Located $$ (Token (KW KW_infixl) _)} 'infixl' { Located $$ (Token (KW KW_infixl) _)}
@ -240,6 +241,8 @@ vtop_decl :: { [TopDecl PName] }
| mbDoc newtype { [exportNewtype Public $2] } | mbDoc newtype { [exportNewtype Public $2] }
| prim_bind { $1 } | prim_bind { $1 }
| private_decls { $1 } | private_decls { $1 }
| abs_fun_decl { $1 }
| abs_type_decl { $1 }
top_decl :: { [TopDecl PName] } top_decl :: { [TopDecl PName] }
: decl { [Decl (TopLevel {tlExport = Public, tlValue = $1 })] } : decl { [Decl (TopLevel {tlExport = Public, tlValue = $1 })] }
@ -256,6 +259,12 @@ prim_bind :: { [TopDecl PName] }
: mbDoc 'primitive' name ':' schema { mkPrimDecl $1 $3 $5 } : mbDoc 'primitive' name ':' schema { mkPrimDecl $1 $3 $5 }
| mbDoc 'primitive' '(' op ')' ':' schema { mkPrimDecl $1 $4 $7 } | mbDoc 'primitive' '(' op ')' ':' schema { mkPrimDecl $1 $4 $7 }
abs_type_decl :: { [TopDecl PName] }
: mbDoc 'abstract' 'type' name ':' kind_fun { [ mkAbsType $1 $4 $6 ] }
abs_fun_decl :: { [TopDecl PName] }
: mbDoc 'abstract' name ':' schema { [mkAbsFun $1 $3 $5] }
doc :: { Located String } doc :: { Located String }
: DOC { mkDoc (fmap tokenText $1) } : DOC { mkDoc (fmap tokenText $1) }
@ -563,6 +572,11 @@ kind :: { Located Kind }
: '#' { Located $1 KNum } : '#' { Located $1 KNum }
| '*' { Located $1 KType } | '*' { Located $1 KType }
kind_fun :: { ([Located Kind], Located Kind) }
: kind { ([], $1) }
| kind '->' kind_fun { let { (xs,x) = $3 } in ($1 : xs, x) }
schema_param :: { TParam PName } schema_param :: { TParam PName }
: ident {% mkTParam $1 Nothing } : ident {% mkTParam $1 Nothing }
| ident ':' kind {% mkTParam (at ($1,$3) $1) (Just (thing $3)) } | ident ':' kind {% mkTParam (at ($1,$3) $1) (Just (thing $3)) }

View File

@ -48,6 +48,8 @@ module Cryptol.Parser.AST
, TopLevel(..) , TopLevel(..)
, Import(..), ImportSpec(..) , Import(..), ImportSpec(..)
, Newtype(..) , Newtype(..)
, AbstractType(..)
, AbstractFun(..)
-- * Interactive -- * Interactive
, ReplInput(..) , ReplInput(..)
@ -122,6 +124,8 @@ modRange m = rCombs $ catMaybes
data TopDecl name = Decl (TopLevel (Decl name)) data TopDecl name = Decl (TopLevel (Decl name))
| TDNewtype (TopLevel (Newtype name)) | TDNewtype (TopLevel (Newtype name))
| Include (Located FilePath) | Include (Located FilePath)
| DAbstractType (TopLevel (AbstractType name))
| DAbstractFun (TopLevel (AbstractFun name))
deriving (Show, Generic, NFData) deriving (Show, Generic, NFData)
data Decl name = DSignature [Located name] (Schema name) data Decl name = DSignature [Located name] (Schema name)
@ -133,6 +137,21 @@ data Decl name = DSignature [Located name] (Schema name)
| DLocated (Decl name) Range | DLocated (Decl name) Range
deriving (Eq, Show, Generic, NFData, Functor) deriving (Eq, Show, Generic, NFData, Functor)
-- XXX Infix ops
data AbstractType name = AbstractType
{ atName :: Located name
, atParams :: [Kind]
, atResult :: Kind
} deriving (Eq,Show,Generic,NFData)
-- XXX Infix ops
data AbstractFun name = AbstractFun
{ afName :: Located name
, afSchema :: Schema name
} deriving (Eq,Show,Generic,NFData)
-- | An import declaration. -- | An import declaration.
data Import = Import { iModule :: !ModName data Import = Import { iModule :: !ModName
, iAs :: Maybe ModName , iAs :: Maybe ModName
@ -468,6 +487,14 @@ instance HasLoc (TopDecl name) where
Decl tld -> getLoc tld Decl tld -> getLoc tld
TDNewtype n -> getLoc n TDNewtype n -> getLoc n
Include lfp -> getLoc lfp Include lfp -> getLoc lfp
DAbstractType d -> getLoc d
DAbstractFun d -> getLoc d
instance HasLoc (AbstractType name) where
getLoc a = getLoc (atName a)
instance HasLoc (AbstractFun name) where
getLoc a = getLoc (afName a)
instance HasLoc (Module name) where instance HasLoc (Module name) where
getLoc m getLoc m
@ -518,6 +545,19 @@ instance (Show name, PPName name) => PP (TopDecl name) where
Decl d -> pp d Decl d -> pp d
TDNewtype n -> pp n TDNewtype n -> pp n
Include l -> text "include" <+> text (show (thing l)) Include l -> text "include" <+> text (show (thing l))
DAbstractFun d -> pp d
DAbstractType d -> pp d
instance (Show name, PPName name) => PP (AbstractType name) where
ppPrec _ a = text "abstract" <+> text "type" <+>
ppPrefixName (atName a) <+> text ":" <+>
foldr ppKFun (pp (atResult a)) (atParams a)
where ppKFun x y = pp x <+> text "->" <+> y
instance (Show name, PPName name) => PP (AbstractFun name) where
ppPrec _ a = text "abstract" <+> ppPrefixName (afName a) <+> text ":"
<+> pp (afSchema a)
instance (Show name, PPName name) => PP (Decl name) where instance (Show name, PPName name) => PP (Decl name) where
ppPrec n decl = ppPrec n decl =
@ -865,6 +905,14 @@ instance NoPos (TopDecl name) where
Decl x -> Decl (noPos x) Decl x -> Decl (noPos x)
TDNewtype n -> TDNewtype(noPos n) TDNewtype n -> TDNewtype(noPos n)
Include x -> Include (noPos x) Include x -> Include (noPos x)
DAbstractFun d -> DAbstractFun (noPos d)
DAbstractType d -> DAbstractType (noPos d)
instance NoPos (AbstractType name) where
noPos a = a
instance NoPos (AbstractFun x) where
noPos x = x { afSchema = noPos (afSchema x) }
instance NoPos a => NoPos (TopLevel a) where instance NoPos a => NoPos (TopLevel a) where
noPos tl = tl { tlValue = noPos (tlValue tl) } noPos tl = tl { tlValue = noPos (tlValue tl) }

View File

@ -117,6 +117,7 @@ $white+ { emit $ White Space }
"infix" { emit $ KW KW_infix } "infix" { emit $ KW KW_infix }
"primitive" { emit $ KW KW_primitive } "primitive" { emit $ KW KW_primitive }
"abstract" { emit $ KW KW_abstract }
@num2 { emitS (numToken 2 . Text.drop 2) } @num2 { emitS (numToken 2 . Text.drop 2) }
@num8 { emitS (numToken 8 . Text.drop 2) } @num8 { emitS (numToken 8 . Text.drop 2) }

View File

@ -391,8 +391,10 @@ data TokenKW = KW_Arith
| KW_infixr | KW_infixr
| KW_infix | KW_infix
| KW_primitive | KW_primitive
| KW_abstract
deriving (Eq, Show, Generic, NFData) deriving (Eq, Show, Generic, NFData)
-- | The named operators are a special case for parsing types, and 'Other' is
-- | The named operators are a special case for parsing types, and 'Other' is -- | The named operators are a special case for parsing types, and 'Other' is
-- used for all other cases that lexed as an operator. -- used for all other cases that lexed as an operator.
data TokenOp = Plus | Minus | Mul | Div | Exp | Mod data TokenOp = Plus | Minus | Mul | Div | Exp | Mod

View File

@ -27,6 +27,8 @@ modExports m = fold (concat [ exportedNames d | d <- mDecls m ])
++ map exportType (names tnamesD td) ++ map exportType (names tnamesD td)
exportedNames (TDNewtype nt) = map exportType (names tnamesNT nt) exportedNames (TDNewtype nt) = map exportType (names tnamesNT nt)
exportedNames (Include {}) = [] exportedNames (Include {}) = []
exportedNames (DAbstractFun f) = [ exportBind ((thing . afName) <$> f) ]
exportedNames (DAbstractType f) = [ exportType ((thing . atName) <$> f) ]
-- | The names defined by a newtype. -- | The names defined by a newtype.
tnamesNT :: Newtype name -> ([Located name], ()) tnamesNT :: Newtype name -> ([Located name], ())

View File

@ -156,6 +156,8 @@ noIncTopDecl :: TopDecl PName -> NoIncM [TopDecl PName]
noIncTopDecl td = case td of noIncTopDecl td = case td of
Decl _ -> return [td] Decl _ -> return [td]
TDNewtype _-> return [td] TDNewtype _-> return [td]
DAbstractType {} -> return [td]
DAbstractFun {} -> return [td]
Include lf -> resolveInclude lf Include lf -> resolveInclude lf
-- | Resolve the file referenced by a include into a list of top-level -- | Resolve the file referenced by a include into a list of top-level

View File

@ -270,11 +270,39 @@ exportNewtype e n = TDNewtype TopLevel { tlExport = e
, tlDoc = Nothing , tlDoc = Nothing
, tlValue = n } , tlValue = n }
mkAbsFun :: Maybe (Located String) ->
Located PName ->
Schema PName ->
TopDecl PName
mkAbsFun mbDoc n s =
DAbstractFun
TopLevel { tlExport = Public
, tlDoc = mbDoc
, tlValue = AbstractFun { afName = n, afSchema = s }
}
mkAbsType :: Maybe (Located String) ->
Located PName ->
([Located Kind],Located Kind) ->
TopDecl PName
mkAbsType mbDoc n (ks,k) =
DAbstractType
TopLevel { tlExport = Public
, tlDoc = mbDoc
, tlValue = AbstractType { atName = n
, atParams = map thing ks
, atResult = thing k }
}
changeExport :: ExportType -> [TopDecl PName] -> [TopDecl PName] changeExport :: ExportType -> [TopDecl PName] -> [TopDecl PName]
changeExport e = map change changeExport e = map change
where where
change (Decl d) = Decl d { tlExport = e } change (Decl d) = Decl d { tlExport = e }
change (TDNewtype n) = TDNewtype n { tlExport = e } change (TDNewtype n) = TDNewtype n { tlExport = e }
change (DAbstractType a) = DAbstractType a { tlExport = e }
change (DAbstractFun a) = DAbstractFun a { tlExport = e }
change td@Include{} = td change td@Include{} = td
mkTypeInst :: Named (Type PName) -> TypeInst PName mkTypeInst :: Named (Type PName) -> TypeInst PName

View File

@ -45,18 +45,19 @@ import Data.Map (Map)
import qualified Data.IntMap as IntMap import qualified Data.IntMap as IntMap
-- | A Cryptol module. -- | A Cryptol module.
data Module = Module { mName :: !ModName data Module = Module { mName :: !ModName
, mExports :: ExportSpec Name , mExports :: ExportSpec Name
, mImports :: [Import] , mImports :: [Import]
, mTySyns :: Map Name TySyn , mTySyns :: Map Name TySyn
, mNewtypes :: Map Name Newtype , mNewtypes :: Map Name Newtype
, mAbsTypes :: Map Name TParam
, mAbsFuns :: Map Name Schema
, mDecls :: [DeclGroup] , mDecls :: [DeclGroup]
} deriving (Show, Generic, NFData) } deriving (Show, Generic, NFData)
data Expr = EList [Expr] Type -- ^ List value (with type of elements) data Expr = EList [Expr] Type -- ^ List value (with type of elements)
| ETuple [Expr] -- ^ Tuple value | ETuple [Expr] -- ^ Tuple value
| ERec [(Ident,Expr)] -- ^ Record value | ERec [(Ident,Expr)] -- ^ Record value
@ -302,5 +303,6 @@ instance PP (WithNames Module) where
-- XXX: Print exports? -- XXX: Print exports?
vcat (map pp mImports) $$ vcat (map pp mImports) $$
-- XXX: Print tysyns -- XXX: Print tysyns
-- XXX: Print abstarct types/functions
vcat (map (ppWithNames nm) mDecls) vcat (map (ppWithNames nm) mDecls)

View File

@ -26,7 +26,9 @@ import Data.Map (Map)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
data TyDecl = TS (P.TySyn Name) | NT (P.Newtype Name) data TyDecl = TS (P.TySyn Name) -- ^ Type synonym
| NT (P.Newtype Name) -- ^ Newtype
| AT (P.AbstractType Name) -- ^ Abstract type
-- | Check for duplicate and recursive type synonyms. -- | Check for duplicate and recursive type synonyms.
-- Returns the type-synonyms in dependency order. -- Returns the type-synonyms in dependency order.
@ -39,6 +41,10 @@ orderTyDecls ts =
concat `fmap` mapM check ordered concat `fmap` mapM check ordered
where where
toMap _ ty@(AT a) =
let x = P.atName a
in ( thing x, x { thing = (ty, []) } )
toMap vs ty@(NT (P.Newtype x as fs)) = toMap vs ty@(NT (P.Newtype x as fs)) =
( thing x ( thing x
, x { thing = (ty, Set.toList $ , x { thing = (ty, Set.toList $
@ -59,6 +65,7 @@ orderTyDecls ts =
getN (TS (P.TySyn x _ _)) = thing x getN (TS (P.TySyn x _ _)) = thing x
getN (NT x) = thing (P.nName x) getN (NT x) = thing (P.nName x)
getN (AT x) = thing (P.atName x)
check (AcyclicSCC x) = return [x] check (AcyclicSCC x) = return [x]
@ -81,6 +88,7 @@ orderBinds bs = mkScc [ (b, map thing defs, Set.toList uses)
class FromDecl d where class FromDecl d where
toBind :: d -> Maybe (P.Bind Name) toBind :: d -> Maybe (P.Bind Name)
toAbsFun :: d -> Maybe (P.AbstractFun Name)
toTyDecl :: d -> Maybe TyDecl toTyDecl :: d -> Maybe TyDecl
isTopDecl :: d -> Bool isTopDecl :: d -> Bool
@ -88,7 +96,11 @@ instance FromDecl (P.TopDecl Name) where
toBind (P.Decl x) = toBind (P.tlValue x) toBind (P.Decl x) = toBind (P.tlValue x)
toBind _ = Nothing toBind _ = Nothing
toAbsFun (P.DAbstractFun d) = Just (P.tlValue d)
toAbsFun _ = Nothing
toTyDecl (P.TDNewtype d) = Just (NT (P.tlValue d)) toTyDecl (P.TDNewtype d) = Just (NT (P.tlValue d))
toTyDecl (P.DAbstractType d) = Just (AT (P.tlValue d))
toTyDecl (P.Decl x) = toTyDecl (P.tlValue x) toTyDecl (P.Decl x) = toTyDecl (P.tlValue x)
toTyDecl _ = Nothing toTyDecl _ = Nothing
@ -99,6 +111,8 @@ instance FromDecl (P.Decl Name) where
toBind (P.DBind b) = return b toBind (P.DBind b) = return b
toBind _ = Nothing toBind _ = Nothing
toAbsFun _ = Nothing
toTyDecl (P.DLocated d _) = toTyDecl d toTyDecl (P.DLocated d _) = toTyDecl d
toTyDecl (P.DType x) = Just (TS x) toTyDecl (P.DType x) = Just (TS x)
toTyDecl _ = Nothing toTyDecl _ = Nothing

View File

@ -24,7 +24,7 @@ import Cryptol.TypeCheck.Monad
import Cryptol.TypeCheck.Solve import Cryptol.TypeCheck.Solve
import Cryptol.TypeCheck.SimpType(tSub,tMul,tExp) import Cryptol.TypeCheck.SimpType(tSub,tMul,tExp)
import Cryptol.TypeCheck.Kind(checkType,checkSchema,checkTySyn, import Cryptol.TypeCheck.Kind(checkType,checkSchema,checkTySyn,
checkNewtype) checkNewtype, checkAbsType)
import Cryptol.TypeCheck.Instantiate import Cryptol.TypeCheck.Instantiate
import Cryptol.TypeCheck.Depends import Cryptol.TypeCheck.Depends
import Cryptol.TypeCheck.Subst (listSubst,apSubst,(@@),emptySubst) import Cryptol.TypeCheck.Subst (listSubst,apSubst,(@@),emptySubst)
@ -49,12 +49,16 @@ inferModule m =
do simplifyAllConstraints do simplifyAllConstraints
ts <- getTSyns ts <- getTSyns
nts <- getNewtypes nts <- getNewtypes
return Module { mName = thing (P.mName m) absTs <- getAbsTypes
, mExports = P.modExports m absFuns <- getAbsFuns
, mImports = map thing (P.mImports m) return Module { mName = thing (P.mName m)
, mTySyns = Map.mapMaybe onlyLocal ts , mExports = P.modExports m
, mNewtypes = Map.mapMaybe onlyLocal nts , mImports = map thing (P.mImports m)
, mDecls = ds1 , mTySyns = Map.mapMaybe onlyLocal ts
, mNewtypes = Map.mapMaybe onlyLocal nts
, mAbsTypes = absTs
, mAbsFuns = absFuns
, mDecls = ds1
} }
where where
onlyLocal (IsLocal, x) = Just x onlyLocal (IsLocal, x) = Just x
@ -830,6 +834,10 @@ inferDs ds continue = checkTyDecls =<< orderTyDecls (mapMaybe toTyDecl ds)
where where
isTopLevel = isTopDecl (head ds) isTopLevel = isTopDecl (head ds)
checkTyDecls (AT t : ts) =
do t1 <- checkAbsType t
withAbsType t1 (checkTyDecls ts)
checkTyDecls (TS t : ts) = checkTyDecls (TS t : ts) =
do t1 <- checkTySyn t do t1 <- checkTySyn t
withTySyn t1 (checkTyDecls ts) withTySyn t1 (checkTyDecls ts)
@ -839,8 +847,19 @@ inferDs ds continue = checkTyDecls =<< orderTyDecls (mapMaybe toTyDecl ds)
withNewtype t1 (checkTyDecls ts) withNewtype t1 (checkTyDecls ts)
-- We checked all type synonyms, now continue with value-level definitions: -- We checked all type synonyms, now continue with value-level definitions:
checkTyDecls [] = checkBinds [] $ orderBinds $ mapMaybe toBind ds checkTyDecls [] =
do xs <- mapM checkAbsFun (mapMaybe toAbsFun ds)
withAbsFuns xs $ checkBinds [] $ orderBinds $ mapMaybe toBind ds
checkAbsFun x =
do (s,gs) <- checkSchema (P.afSchema x)
case gs of
[] -> return ()
_ ->
recordError $ ErrorMsg $ text $
"XXX: Left-over goals while validating schema"
let n = thing (P.afName x)
return (n,s)
checkBinds decls (CyclicSCC bs : more) = checkBinds decls (CyclicSCC bs : more) =
do bs1 <- inferBinds isTopLevel True bs do bs1 <- inferBinds isTopLevel True bs

View File

@ -13,11 +13,13 @@ module Cryptol.TypeCheck.Kind
, checkSchema , checkSchema
, checkNewtype , checkNewtype
, checkTySyn , checkTySyn
, checkAbsType
) where ) where
import qualified Cryptol.Parser.AST as P import qualified Cryptol.Parser.AST as P
import Cryptol.Parser.AST (Named(..)) import Cryptol.Parser.AST (Named(..))
import Cryptol.Parser.Position import Cryptol.Parser.Position
import Cryptol.ModuleSystem.Name(nameUnique)
import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.AST
import Cryptol.TypeCheck.Monad hiding (withTParams) import Cryptol.TypeCheck.Monad hiding (withTParams)
import Cryptol.TypeCheck.SimpType(tRebuild) import Cryptol.TypeCheck.SimpType(tRebuild)
@ -52,6 +54,16 @@ checkSchema (P.Forall xs ps t mb) =
Nothing -> id Nothing -> id
Just r -> inRange r Just r -> inRange r
checkAbsType :: P.AbstractType Name -> InferM TParam
checkAbsType a =
do let k = foldr (:->) (cvtK (P.atResult a)) (map cvtK (P.atParams a))
n = thing (P.atName a)
return TParam { tpUnique = nameUnique n -- XXX: ok to reuse?
, tpKind = k
, tpName = Just n
}
-- | Check a type-synonym declaration. -- | Check a type-synonym declaration.
checkTySyn :: P.TySyn Name -> InferM TySyn checkTySyn :: P.TySyn Name -> InferM TySyn
checkTySyn (P.TySyn x as t) = checkTySyn (P.TySyn x as t) =
@ -151,13 +163,16 @@ withTParams allowWildCards xs m =
zip' [] _ = [] zip' [] _ = []
zip' (a:as) ~(t:ts) = (P.tpName a, fmap cvtK (P.tpKind a), t) : zip' as ts zip' (a:as) ~(t:ts) = (P.tpName a, fmap cvtK (P.tpKind a), t) : zip' as ts
cvtK P.KNum = KNum
cvtK P.KType = KType
duplicates = [ RepeatedTyParams ds duplicates = [ RepeatedTyParams ds
| ds@(_ : _ : _) <- groupBy ((==) `on` P.tpName) | ds@(_ : _ : _) <- groupBy ((==) `on` P.tpName)
$ sortBy (compare `on` P.tpName) xs ] $ sortBy (compare `on` P.tpName) xs ]
cvtK :: P.Kind -> Kind
cvtK P.KNum = KNum
cvtK P.KType = KType
-- | Check an application of a type constant. -- | Check an application of a type constant.
tcon :: TCon -- ^ Type constant being applied tcon :: TCon -- ^ Type constant being applied
-> [P.Type Name] -- ^ Type parameters -> [P.Type Name] -- ^ Type parameters
@ -167,7 +182,7 @@ tcon tc ts0 k =
do (ts1,k1) <- appTy ts0 (kindOf tc) do (ts1,k1) <- appTy ts0 (kindOf tc)
checkKind (TCon tc ts1) k k1 checkKind (TCon tc ts1) k k1
-- | Check a use of a type-synonym, newtype, or scoped-type variable. -- | Check a use of a type-synonym, newtype, abs type, or scoped-type variable.
tySyn :: Bool -- ^ Should we check for scoped type vars. tySyn :: Bool -- ^ Should we check for scoped type vars.
-> Name -- ^ Name of type sysnonym -> Name -- ^ Name of type sysnonym
-> [P.Type Name]-- ^ Type synonym parameters -> [P.Type Name]-- ^ Type synonym parameters
@ -195,12 +210,26 @@ tySyn scoped x ts k =
ts2 <- checkParams (ntParams nt) ts1 ts2 <- checkParams (ntParams nt) ts1
return (TCon tc ts2) return (TCon tc ts2)
-- Maybe it is a scoped type variable? -- Maybe it is an abstract type?
Nothing Nothing ->
| scoped -> kExistTVar x $ fromMaybe KNum k do mbA <- kLookupAbsType x
| otherwise -> case mbA of
do kRecordError $ UndefinedTypeSynonym x Just a ->
kNewType (text "type synonym" <+> pp x) $ fromMaybe KNum k do let tc = abstractTypeTCon a
(ts1,k1) <- appTy ts (kindOf tc)
case k of
Just ks
| ks /= k1 -> kRecordError $ KindMismatch ks k1
_ -> return ()
return (TCon tc ts1)
-- Maybe it is a scoped type variable?
Nothing
| scoped -> kExistTVar x $ fromMaybe KNum k
| otherwise ->
do kRecordError $ UndefinedTypeSynonym x
kNewType (text "type synonym" <+> pp x) $
fromMaybe KNum k
where where
checkParams as ts1 checkParams as ts1
| paramHave == paramNeed = return ts1 | paramHave == paramNeed = return ts1

View File

@ -59,6 +59,7 @@ data InferInput = InferInput
, inpVars :: Map Name Schema -- ^ Variables that are in scope , inpVars :: Map Name Schema -- ^ Variables that are in scope
, inpTSyns :: Map Name TySyn -- ^ Type synonyms that are in scope , inpTSyns :: Map Name TySyn -- ^ Type synonyms that are in scope
, inpNewtypes :: Map Name Newtype -- ^ Newtypes in scope , inpNewtypes :: Map Name Newtype -- ^ Newtypes in scope
, inpNameSeeds :: NameSeeds -- ^ Private state of type-checker , inpNameSeeds :: NameSeeds -- ^ Private state of type-checker
, inpMonoBinds :: Bool -- ^ Should local bindings without , inpMonoBinds :: Bool -- ^ Should local bindings without
-- signatures be monomorphized? -- signatures be monomorphized?
@ -67,9 +68,9 @@ data InferInput = InferInput
, inpSearchPath :: [FilePath] , inpSearchPath :: [FilePath]
-- ^ Where to look for Cryptol theory file. -- ^ Where to look for Cryptol theory file.
, inpPrimNames :: !PrimMap -- ^ The mapping from 'Ident' to 'Name', , inpPrimNames :: !PrimMap
-- for names that the typechecker -- ^ This is used when the type-checker needs to refer to a predefined
-- needs to refer to. -- identifier (e.g., @demote@).
, inpSupply :: !Supply -- ^ The supply for fresh name generation , inpSupply :: !Supply -- ^ The supply for fresh name generation
} deriving Show } deriving Show
@ -110,6 +111,9 @@ runInferM info (IM m) = CrySAT.withSolver (inpSolverConfig info) $ \solver ->
, iTVars = [] , iTVars = []
, iTSyns = fmap mkExternal (inpTSyns info) , iTSyns = fmap mkExternal (inpTSyns info)
, iNewtypes = fmap mkExternal (inpNewtypes info) , iNewtypes = fmap mkExternal (inpNewtypes info)
, iAbsTypes = Map.empty
, iAbsFuns = Map.empty
, iSolvedHasLazy = iSolvedHas finalRW -- RECURSION , iSolvedHasLazy = iSolvedHas finalRW -- RECURSION
, iMonoBinds = inpMonoBinds info , iMonoBinds = inpMonoBinds info
, iSolver = solver , iSolver = solver
@ -206,6 +210,12 @@ data RO = RO
-- at the top-level, but then there can't be a newtype with the -- at the top-level, but then there can't be a newtype with the
-- same name (this should be caught by the renamer). -- same name (this should be caught by the renamer).
, iAbsTypes :: Map Name TParam
-- ^ Abstract types
, iAbsFuns :: Map Name Schema
-- ^ Abstract functions
, iSolvedHasLazy :: Map Int (Expr -> Expr) , iSolvedHasLazy :: Map Int (Expr -> Expr)
-- ^ NOTE: This field is lazy in an important way! It is the -- ^ NOTE: This field is lazy in an important way! It is the
-- final version of `iSolvedHas` in `RW`, and the two are tied -- final version of `iSolvedHas` in `RW`, and the two are tied
@ -524,9 +534,14 @@ lookupVar x =
do mbNT <- lookupNewtype x do mbNT <- lookupNewtype x
case mbNT of case mbNT of
Just nt -> return (ExtVar (newtypeConType nt)) Just nt -> return (ExtVar (newtypeConType nt))
Nothing -> do recordError $ UndefinedVariable x Nothing ->
a <- newType (text "type of" <+> pp x) KType do mbAbsFun <- lookupAbsFun x
return $ ExtVar $ Forall [] [] a case mbAbsFun of
Just af -> return (ExtVar af)
Nothing ->
do recordError $ UndefinedVariable x
a <- newType (text "type of" <+> pp x) KType
return $ ExtVar $ Forall [] [] a
-- | Lookup a type variable. Return `Nothing` if there is no such variable -- | Lookup a type variable. Return `Nothing` if there is no such variable
-- in scope, in which case we must be dealing with a type constant. -- in scope, in which case we must be dealing with a type constant.
@ -542,6 +557,14 @@ lookupTSyn x = fmap (fmap snd . Map.lookup x) getTSyns
lookupNewtype :: Name -> InferM (Maybe Newtype) lookupNewtype :: Name -> InferM (Maybe Newtype)
lookupNewtype x = fmap (fmap snd . Map.lookup x) getNewtypes lookupNewtype x = fmap (fmap snd . Map.lookup x) getNewtypes
-- | Lookup the kind of an abstract type
lookupAbsType :: Name -> InferM (Maybe TParam)
lookupAbsType x = Map.lookup x <$> getAbsTypes
-- | Lookup the schema for an abstract function.
lookupAbsFun :: Name -> InferM (Maybe Schema)
lookupAbsFun x = Map.lookup x <$> getAbsFuns
-- | Check if we already have a name for this existential type variable and, -- | Check if we already have a name for this existential type variable and,
-- if so, return the definition. If not, try to create a new definition, -- if so, return the definition. If not, try to create a new definition,
-- if this is allowed. If not, returns nothing. -- if this is allowed. If not, returns nothing.
@ -574,6 +597,14 @@ getTSyns = IM $ asks iTSyns
getNewtypes :: InferM (Map Name (DefLoc,Newtype)) getNewtypes :: InferM (Map Name (DefLoc,Newtype))
getNewtypes = IM $ asks iNewtypes getNewtypes = IM $ asks iNewtypes
-- | Returns the abstract type declarations
getAbsFuns :: InferM (Map Name Schema)
getAbsFuns = IM $ asks iAbsFuns
-- | Returns the abstract function declarations
getAbsTypes :: InferM (Map Name TParam)
getAbsTypes = IM $ asks iAbsTypes
-- | Get the set of bound type variables that are in scope. -- | Get the set of bound type variables that are in scope.
getTVars :: InferM (Set Name) getTVars :: InferM (Set Name)
getTVars = IM $ asks $ Set.fromList . mapMaybe tpName . iTVars getTVars = IM $ asks $ Set.fromList . mapMaybe tpName . iTVars
@ -638,6 +669,14 @@ withNewtype t (IM m) =
IM $ mapReader IM $ mapReader
(\r -> r { iNewtypes = Map.insert (ntName t) (IsLocal,t) (\r -> r { iNewtypes = Map.insert (ntName t) (IsLocal,t)
(iNewtypes r) }) m (iNewtypes r) }) m
withAbsType :: TParam -> InferM a -> InferM a
withAbsType a (IM m) =
case tpName a of
Nothing -> panic "withAbsType" ["Abstract type without a name"]
Just n ->
IM $ mapReader
(\r -> r { iAbsTypes = Map.insert n a (iAbsTypes r) })
m
-- | The sub-computation is performed with the given variable in scope. -- | The sub-computation is performed with the given variable in scope.
withVarType :: Name -> VarType -> InferM a -> InferM a withVarType :: Name -> VarType -> InferM a -> InferM a
@ -650,6 +689,13 @@ withVarTypes xs m = foldr (uncurry withVarType) m xs
withVar :: Name -> Schema -> InferM a -> InferM a withVar :: Name -> Schema -> InferM a -> InferM a
withVar x s = withVarType x (ExtVar s) withVar x s = withVarType x (ExtVar s)
-- | The sub-computation is performed with the given abstract function in scope.
withAbsFuns :: [(Name, Schema)] -> InferM a -> InferM a
withAbsFuns xs (IM m) =
IM $ mapReader (\r -> r { iAbsFuns = foldr add (iAbsFuns r) xs }) m
where
add (x,s) = Map.insert x s
-- | The sub-computation is performed with the given variables in scope. -- | The sub-computation is performed with the given variables in scope.
withMonoType :: (Name,Located Type) -> InferM a -> InferM a withMonoType :: (Name,Located Type) -> InferM a -> InferM a
@ -770,6 +816,9 @@ kLookupTSyn x = kInInferM $ lookupTSyn x
kLookupNewtype :: Name -> KindM (Maybe Newtype) kLookupNewtype :: Name -> KindM (Maybe Newtype)
kLookupNewtype x = kInInferM $ lookupNewtype x kLookupNewtype x = kInInferM $ lookupNewtype x
kLookupAbsType :: Name -> KindM (Maybe TParam)
kLookupAbsType x = kInInferM $ lookupAbsType x
kExistTVar :: Name -> Kind -> KindM Type kExistTVar :: Name -> Kind -> KindM Type
kExistTVar x k = kInInferM $ existVar x k kExistTVar x k = kInInferM $ existVar x k

View File

@ -43,7 +43,10 @@ data Schema = Forall { sVars :: [TParam], sProps :: [Prop], sType :: Type }
-- | Type parameters. -- | Type parameters.
data TParam = TParam { tpUnique :: !Int -- ^ Parameter identifier data TParam = TParam { tpUnique :: !Int -- ^ Parameter identifier
, tpKind :: Kind -- ^ Kind of parameter , tpKind :: Kind -- ^ Kind of parameter
, tpName :: Maybe Name -- ^ Name from source, if any. , tpName :: Maybe Name
-- ^ Name from source, if any.
-- INVARIANT: if this arouse from an abstract type
-- then the name will alwyas be defined.
} }
deriving (Generic, NFData, Show) deriving (Generic, NFData, Show)
@ -120,6 +123,15 @@ data UserTC = UserTC Name Kind
deriving (Show, Generic, NFData) deriving (Show, Generic, NFData)
abstractTypeTCon :: TParam -> TCon
abstractTypeTCon tp = TC $ TCNewtype $ UserTC nm k
where
nm = case tpName tp of
Just n -> n
Nothing -> panic "abstractTypeTCon" ["Missing name"]
k = tpKind tp
data TCErrorMessage = TCErrorMessage data TCErrorMessage = TCErrorMessage
{ tcErrorMessage :: !String { tcErrorMessage :: !String
-- XXX: Add location? -- XXX: Add location?