{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} module Trans.RawToHaskell (fileToModules) where import Data.Word import Data.Maybe (fromJust) import Data.String (fromString) import GHC.Exts (fromList) import qualified Data.Text as T import IR.Haskell import Trans.ToHaskellCommon import qualified Capnp import qualified Capnp.Untyped.Pure as Untyped import qualified IR.Common as C import qualified IR.Name as Name import qualified IR.Raw as Raw tMutMsg :: Type tMutMsg = TApp (tgName ["Message"] "MutMsg" ) [TVar "s"] tConstMsg :: Type tConstMsg = tgName ["Message"] "ConstMsg" fileToModules :: Raw.File -> [Module] fileToModules file = [ fileToMainModule file , fileToModuleAlias file ] fileToModuleAlias :: Raw.File -> Module fileToModuleAlias Raw.File{fileName, fileId} = let reExport = ["Capnp", "Gen"] ++ makeModName fileName in Module { modName = idToModule fileId , modLangPragmas = [] , modExports = Just [ExportMod reExport] , modImports = [ ImportAll { parts = reExport } ] , modDecls = [] } fileToMainModule :: Raw.File -> Module fileToMainModule Raw.File{fileName, fileId, decls} = fixImports $ Module { modName = ["Capnp", "Gen"] ++ makeModName fileName , modLangPragmas = [ "FlexibleContexts" , "FlexibleInstances" , "MultiParamTypeClasses" , "TypeFamilies" , "DeriveGeneric" , "OverloadedStrings" ] , modExports = Nothing , modImports = [ imp ["Capnp", "Message"] "Message" , imp ["Capnp", "Untyped"] "Untyped" , imp ["Capnp", "Basics"] "Basics" , imp ["Capnp", "GenHelpers"] "GenHelpers" , imp ["Capnp", "Classes"] "Classes" , imp ["GHC", "Generics"] "Generics" -- So we can treat 'Word1' the same as 'Word16' etc. , imp ["Capnp", "Bits"] "Std_" , imp ["Data", "Maybe"] "Std_" , imp ["Capnp", "GenHelpers", "ReExports", "Data", "ByteString"] "BS" ] , modDecls = concatMap (declToDecls fileId) decls } where imp parts importAs = ImportAs {parts, importAs} declToDecls :: Word64 -> Raw.Decl -> [Decl] declToDecls thisMod Raw.UnionVariant{parentTypeCtor, tagOffset, unionDataCtors} = let unknownCtor = Name.mkSub parentTypeCtor "unknown'" typeCtor = Name.mkSub parentTypeCtor "" in [ DcData Data { dataName = Name.localToUnQ typeCtor , dataNewtype = False , typeArgs = [TVar "msg"] , dataVariants = [ DataVariant { dvCtorName = Name.localToUnQ dataCtor , dvArgs = APos $ case locType of C.VoidField -> [] _ -> [ typeToType thisMod (C.fieldType locType) (TVar "msg") ] } | Raw.Variant{name=dataCtor, locType} <- unionDataCtors ] ++ [ DataVariant { dvCtorName = Name.localToUnQ unknownCtor , dvArgs = APos [ TPrim $ C.PrimInt $ C.IntType C.Unsigned C.Sz16 ] } ] , derives = [] } , instance_ [] ["Classes"] "FromStruct" [TVar "msg", TApp (TLName typeCtor) [TVar "msg"]] [ iValue "fromStruct" [PVar "struct"] $ EDo [ DoBind "tag" (EApp (egName ["GenHelpers"] "getTag") [ ELName "struct" , EInt (fromIntegral tagOffset) ] ) ] (ECase (ELName "tag") $ [ ( PInt $ fromIntegral tagValue , case locType of C.VoidField -> EApp (eStd_ "pure") [ELName name] C.HereField _ -> EFApp (ELName name) [ EApp (egName ["Classes"] "fromStruct") [ELName "struct"] ] C.DataField loc _ -> EFApp (ELName name) [eGetWordField (ELName "struct") loc] C.PtrField idx _ -> EFApp (ELName name) [ EDo [DoBind "ptr" $ EApp (egName ["Untyped"] "getPtr") [ EInt $ fromIntegral idx , ELName "struct" ] ] (EApp (egName ["Classes"] "fromPtr") [ EApp (egName ["Untyped"] "message") [ELName "struct"] , ELName "ptr" ] ) ] ) | Raw.Variant{name, tagValue, locType} <- unionDataCtors ] ++ [ ( PVar "_" , EApp (eStd_ "pure") [ EApp (ELName unknownCtor) [ EApp (eStd_ "fromIntegral") [ELName "tag"] ] ] ) ] ) ] ] declToDecls _thisMod Raw.Enum{typeCtor, dataCtors} = let listCtor = Name.mkSub typeCtor "List_" unknownCtor = Name.mkSub typeCtor "unknown'" in [ DcData Data { dataName = Name.localToUnQ typeCtor , dataNewtype = False , typeArgs = [] , dataVariants = map enumerantToVariant dataCtors ++ [ DataVariant { dvCtorName = Name.localToUnQ unknownCtor , dvArgs = APos [ TPrim $ C.PrimInt $ C.IntType C.Unsigned C.Sz16 ] } ] , derives = [ "Std_.Show" , "Std_.Read" , "Std_.Eq" , "Generics.Generic" ] } , mkIsWordInstance typeCtor dataCtors unknownCtor -- An Enum instance that just wraps the IsWord instance: , instance_ [] ["Std_"] "Enum" [TLName typeCtor] [ iValue "fromEnum" [PVar "x"] $ EApp (eStd_ "fromIntegral") [ EApp (egName ["Classes"] "toWord") [ELName "x"] ] , iValue "toEnum" [PVar "x"] $ EApp (egName ["Classes"] "fromWord") [ EApp (eStd_ "fromIntegral") [ELName "x"] ] ] -- lists: , instance_ [] ["Basics"] "ListElem" [TVar "msg", TLName typeCtor] [ IdData Data { dataName = "List" , typeArgs = [ TVar "msg" , TLName typeCtor ] , dataVariants = [ DataVariant { dvCtorName = Name.localToUnQ listCtor , dvArgs = APos [ TApp (tgName ["Untyped"] "ListOf") [ TVar "msg" , tStd_ "Word16" ] ] } ] , derives = [] , dataNewtype = True } , iValue "index" [PVar "i", PLCtor listCtor [PVar "l"]] $ EFApp (egName ["Classes"] "fromWord") [ EFApp (eStd_ "fromIntegral") [ EApp (egName ["Untyped"] "index") [ ELName "i" , ELName "l" ] ] ] , iValue "listFromPtr" [PVar "msg", PVar "ptr"] $ EFApp (ELName listCtor) [ EApp (egName ["Classes"] "fromPtr") [ ELName "msg" , ELName "ptr" ] ] , iValue "toUntypedList" [PLCtor listCtor [PVar "l"]] $ EApp (egName ["Untyped"] "List16") [ELName "l"] , iValue "length" [PLCtor listCtor [PVar "l"]] $ EApp (egName ["Untyped"] "length") [ELName "l"] ] , instance_ [] ["Classes"] "MutListElem" [TVar "s", TLName typeCtor] [ iValue "setIndex" [PVar "elt", PVar "i", PLCtor listCtor [PVar "l"]] $ EApp (egName ["Untyped"] "setIndex") [ EApp (eStd_ "fromIntegral") [ EApp (egName ["Classes"] "toWord") [ELName "elt"] ] , ELName "i" , ELName "l" ] , iValue "newList" [PVar "msg", PVar "size"] $ EFApp (ELName listCtor) [ EApp (egName ["Untyped"] "allocList16") [ ELName "msg" , ELName "size" ] ] ] ] where enumerantToVariant variantName = DataVariant { dvCtorName = Name.localToUnQ variantName , dvArgs = APos [] } declToDecls _thisMod Raw.InterfaceWrapper{typeCtor} = let dataCtor = Name.mkSub typeCtor "newtype_" in [ newtypeWrapper typeCtor ["msg"] $ TApp (tStd_ "Maybe") [ TApp (tgName ["Untyped"] "Cap") [TVar "msg"] ] , wrapperFromPtr typeCtor dataCtor , instance_ [] ["Classes"] "ToPtr" [ TVar "s" , TApp (TLName typeCtor) [TApp (tgName ["Message"] "MutMsg") [TVar "s"]] ] [ iValue "toPtr" [PVar "msg", PLCtor dataCtor [PGCtor (std_ "Nothing") []]] (EApp (eStd_ "pure") [eStd_ "Nothing"]) , iValue "toPtr" [PVar "msg", PLCtor dataCtor [PGCtor (std_ "Just") [PVar "cap"]]] (EApp (eStd_ "pure") [ EApp (eStd_ "Just") [ EApp (egName ["Untyped"] "PtrCap") [ELName "cap"] ] ] ) ] ] declToDecls _thisMod Raw.StructWrapper{typeCtor} = let dataCtor = Name.mkSub typeCtor "newtype_" in [ newtypeWrapper typeCtor ["msg"] $ TApp (tgName ["Untyped"] "Struct") [TVar "msg"] -- There are several type classes that are defined for all structs: , instance_ [] ["Untyped"] "TraverseMsg" [TLName typeCtor] [ iValue "tMsg" [PVar "f", PLCtor dataCtor [PVar "s"]] $ EFApp (ELName dataCtor) [EApp (egName ["Untyped"] "tMsg") [ELName "f", ELName "s"]] ] , instance_ [] ["Classes"] "FromStruct" [ TVar "msg", TApp (TLName typeCtor) [TVar "msg"] ] [ iValue "fromStruct" [PVar "struct"] $ EApp (eStd_ "pure") [EApp (ELName dataCtor) [ELName "struct"]] ] , instance_ [] ["Classes"] "ToStruct" [TVar "msg", TApp (TLName typeCtor) [TVar "msg"]] [ iValue "toStruct" [PLCtor dataCtor [PVar "struct"]] (ELName "struct") ] , instance_ [] ["Untyped"] "HasMessage" [TApp (TLName typeCtor) [TVar "msg"]] [ IdType $ TypeAlias "InMessage" [ TApp (TLName typeCtor) [TVar "msg"] ] (TVar "msg") , iValue "message" [PLCtor dataCtor [PVar "struct"]] (EApp (egName ["Untyped"] "message") [ELName "struct"]) ] , instance_ [] ["Untyped"] "MessageDefault" [TApp (TLName typeCtor) [TVar "msg"]] [ iValue "messageDefault" [PVar "msg"] $ EApp (ELName dataCtor) [ EApp (egName ["Untyped"] "messageDefault") [ELName "msg"] ] ] ] declToDecls _thisMod Raw.StructInstances{typeCtor, dataWordCount, pointerCount} = let listCtor = Name.mkSub typeCtor "List_" dataCtor = Name.mkSub typeCtor "newtype_" in [ wrapperFromPtr typeCtor dataCtor , instance_ [] ["Classes"] "ToPtr" [ TVar "s" , TApp (TLName typeCtor) [TApp (tgName ["Message"] "MutMsg") [TVar "s"]] ] [ iValue "toPtr" [PVar "msg", PLCtor dataCtor [PVar "struct"]] (EApp (egName ["Classes"] "toPtr") [ ELName "msg" , ELName "struct" ] ) ] , instance_ [] ["Classes"] "Allocate" [ TVar "s" , TApp (TLName typeCtor) [TApp (tgName ["Message"] "MutMsg") [TVar "s"]] ] [ iValue "new" [PVar "msg"] $ EFApp (ELName dataCtor) [ EApp (egName ["Untyped"] "allocStruct") [ ELName "msg" , EInt $ fromIntegral dataWordCount , EInt $ fromIntegral pointerCount ] ] ] , instance_ [] ["Basics"] "ListElem" [ TVar "msg" , TApp (TLName typeCtor) [TVar "msg"] ] [ IdData Data { dataName = "List" , typeArgs = [ TVar "msg" , TApp (TLName typeCtor) [TVar "msg"] ] , dataVariants = [ DataVariant { dvCtorName = Name.localToUnQ listCtor , dvArgs = APos [ TApp (tgName ["Untyped"] "ListOf") [ TVar "msg" , TApp (tgName ["Untyped"] "Struct") [TVar "msg"] ] ] } ] , derives = [] , dataNewtype = True } , iValue "listFromPtr" [PVar "msg", PVar "ptr"] $ EFApp (ELName listCtor) [ EApp (egName ["Classes"] "fromPtr") [ELName "msg", ELName "ptr"] ] , iValue "toUntypedList" [PLCtor listCtor [PVar "l"]] $ EApp (egName ["Untyped"] "ListStruct") [ELName "l"] , iValue "length" [PLCtor listCtor [PVar "l"]] $ EApp (egName ["Untyped"] "length") [ELName "l"] , iValue "index" [PVar "i", PLCtor listCtor [PVar "l"]] $ EDo [ DoBind "elt" $ EApp (egName ["Untyped"] "index") [ ELName "i" , ELName "l" ] ] ( EApp (egName ["Classes"] "fromStruct") [ELName "elt"] ) ] , instance_ [] ["Basics"] "MutListElem" [ TVar "s" , TApp (TLName typeCtor) [ TApp (tgName ["Message"] "MutMsg") [TVar "s"] ] ] [ iValue "setIndex" [ PLCtor dataCtor [PVar "elt"] , PVar "i" , PLCtor listCtor [PVar "l"] ] (EApp (egName ["Untyped"] "setIndex") [ ELName "elt" , ELName "i" , ELName "l" ] ) , iValue "newList" [PVar "msg", PVar "len"] $ EFApp (ELName listCtor) [ EApp (egName ["Untyped"] "allocCompositeList") [ ELName "msg" , EInt $ fromIntegral dataWordCount , EInt $ fromIntegral pointerCount , ELName "len" ] ] ] ] declToDecls thisMod Raw.Getter{fieldName, fieldLocType, containerType} = let containerDataCtor = Name.mkSub containerType "newtype_" in [ DcValue { typ = TCtx [readCtx "m" "msg"] (TFn [ TApp (TLName containerType) [ TVar "msg" ] , TApp (TVar "m") [ typeToType thisMod (C.fieldType fieldLocType) (TVar "msg") ] ] ) , def = DfValue { name = Name.getterName fieldName , params = [PLCtor containerDataCtor [PVar "struct"]] , value = case fieldLocType of C.DataField dataLoc _ -> eGetWordField (ELName "struct") dataLoc C.PtrField idx _ -> EDo [ DoBind "ptr" $ EApp (egName ["Untyped"] "getPtr") [ EInt (fromIntegral idx) , ELName "struct" ] ] (EApp (egName ["Classes"] "fromPtr") [ EApp (egName ["Untyped"] "message") [ELName "struct"] , ELName "ptr" ] ) C.HereField _ -> EApp (egName ["Classes"] "fromStruct") [ELName "struct"] C.VoidField -> EApp (eStd_ "pure") [ETup []] } } ] declToDecls thisMod Raw.Setter{fieldName, fieldLocType, containerType, tag} = -- XXX: the way this is organized is a little gross; conceptually we have -- two kinds of setters: -- -- * Those that actually take an argument, and return unit. -- * Those that are groups, in which case they don't take an argument, -- and return the value. -- -- The latter are only actually useful if the group is a union member, -- but we generate them regardless. -- -- The below is a little ugly in that there's a bit to much conditional -- logic strewn about because of the above. let containerDataCtor = Name.mkSub containerType "newtype_" fieldType = typeToType thisMod (C.fieldType fieldLocType) tMutMsg in [ DcValue { typ = TCtx [rwCtx "m" "s"] (case fieldLocType of C.HereField _ -> TFn [ TApp (TLName containerType) [tMutMsg] , TApp (TVar "m") [fieldType] ] C.VoidField -> TFn -- We don't need to pass in the redundant () value. [ TApp (TLName containerType) [tMutMsg] , TApp (TVar "m") [fieldType] ] _ -> TFn [ TApp (TLName containerType) [tMutMsg] , fieldType , TApp (TVar "m") [TUnit] ] ) , def = DfValue { name = Name.setterName fieldName , params = case fieldLocType of C.HereField _ -> [ PLCtor containerDataCtor [PVar "struct"] ] C.VoidField -> [ PLCtor containerDataCtor [PVar "struct"] ] _ -> [ PLCtor containerDataCtor [PVar "struct"] , PVar "value" ] , value = case tag of Just tagSetter -> EDo [DoE $ eSetTag tagSetter] (eSetValue fieldLocType) Nothing -> eSetValue fieldLocType } } ] declToDecls _thisMod Raw.HasFn{fieldName, containerType, ptrIndex} = let containerDataCtor = Name.mkSub containerType "newtype_" in [ DcValue { typ = TCtx [readCtx "m" "msg"] (TFn [ TApp (TLName containerType) [ TVar "msg" ] , TApp (TVar "m") [tStd_ "Bool"] ] ) , def = DfValue { name = Name.hasFnName fieldName , params = [PLCtor containerDataCtor [PVar "struct"]] , value = EFApp (eStd_ "isJust") [ EApp (egName ["Untyped"] "getPtr") [ EInt $ fromIntegral ptrIndex , ELName "struct" ] ] } } ] declToDecls thisMod Raw.NewFn{fieldName, containerType, fieldLocType, newFnType} = -- TODO(cleanup): I(zenhack) am a little unhappy with having several case -- expressions to distinguish struct vs non-struct; we should refactor. let fieldType = typeToType thisMod (C.fieldType fieldLocType) tMutMsg in [ DcValue { typ = TCtx [rwCtx "m" "s"] (TFn $ concat [ case newFnType of -- length Raw.NewStruct -> [] _ -> [tStd_ "Int"] , [TApp (TLName containerType) [tMutMsg]] , [TApp (TVar "m") [fieldType]] ] ) , def = DfValue { name = Name.newFnName fieldName , params = case newFnType of Raw.NewStruct -> [PVar "struct"] _ -> [PVar "len", PVar "struct"] , value = EDo [ DoBind "result" $ let message = EApp (egName ["Untyped"] "message") [ELName "struct"] in case newFnType of Raw.NewStruct -> EApp (egName ["Classes"] "new") [message] Raw.NewList -> EApp (egName ["Classes"] "newList") [message, ELName "len"] Raw.NewText -> EApp (egName ["Basics"] "newText") [message, ELName "len"] Raw.NewData -> EApp (egName ["Basics"] "newData") [message, ELName "len"] , DoE $ EApp (ELName $ Name.mkLocal Name.emptyNS (Name.setterName fieldName)) [ ELName "struct" , ELName "result" ] ] (EApp (eStd_ "pure") [ELName "result"]) } } ] declToDecls _thisMod Raw.Constant{ name, value=C.VoidValue } = [ DcValue { typ = TUnit , def = DfValue { name = Name.localToUnQ name , params = [] , value = ETup [] } } ] declToDecls thisMod Raw.Constant{ name, value=C.WordValue ty val } = [ DcValue { typ = typeToType thisMod (C.WordType ty) tConstMsg , def = DfValue { name = Name.localToUnQ name , params = [] , value = EApp (egName ["Classes"] "fromWord") [EInt $ fromIntegral val] } } ] declToDecls thisMod Raw.Constant{ name, value=C.PtrValue ty val } = [ DcValue { typ = typeToType thisMod (C.PtrType ty) tConstMsg , def = DfValue { name = Name.localToUnQ name , params = [] , value = EApp (egName ["GenHelpers"] "getPtrConst") [ETypeAnno (EBytes (makePtrBytes val)) (tgName ["BS"] "ByteString")] } } ] where makePtrBytes ptr = Capnp.msgToLBS $ fromJust $ Capnp.createPure Capnp.defaultLimit $ do msg <- Capnp.newMessage Nothing rootPtr <- Capnp.cerialize msg $ Untyped.Struct (fromList []) (fromList [ptr]) Capnp.setRoot rootPtr pure msg eSetValue :: C.FieldLocType Name.CapnpQ -> Exp eSetValue = \case C.DataField dataLoc ty -> eSetWordField (ELName "struct") (ETypeAnno (EApp (eStd_ "fromIntegral") [EApp (egName ["Classes"] "toWord") [ELName "value"] ] ) (tStd_ $ fromString $ "Word" <> show (C.dataFieldSize ty)) ) dataLoc C.PtrField idx _ -> EDo [ DoBind "ptr" $ EApp (egName ["Classes"] "toPtr") [ EApp (egName ["Untyped"] "message") [ELName "struct"] , ELName "value" ] ] (EApp (egName ["Untyped"] "setPtr") [ ELName "ptr" , EInt (fromIntegral idx) , ELName "struct" ] ) C.HereField _ -> -- We actually just fetch the field in this case; this only happens for -- groups (and unions, but the tag is handled separately in that case). EApp (egName ["Classes"] "fromStruct") [ELName "struct"] C.VoidField -> EApp (eStd_ "pure") [ETup []] eSetTag :: Raw.TagSetter -> Exp eSetTag Raw.TagSetter{tagOffset, tagValue} = eSetWordField (ELName "struct") (ETypeAnno (EInt $ fromIntegral tagValue) (TPrim $ C.PrimInt $ C.IntType C.Unsigned C.Sz16) ) (Raw.tagOffsetToDataLoc tagOffset) eSetWordField :: Exp -> Exp -> C.DataLoc -> Exp eSetWordField struct value C.DataLoc{dataIdx, dataOff, dataDef} = EApp (egName ["GenHelpers"] "setWordField") [ struct , value , EInt $ fromIntegral dataIdx , EInt $ fromIntegral dataOff , EInt $ fromIntegral dataDef ] -- | Make an instance of the IsWord type class for an enum. mkIsWordInstance :: Name.LocalQ -> [Name.LocalQ] -> Name.LocalQ -> Decl mkIsWordInstance typeCtor dataCtors unknownCtor = instance_ [] ["Classes"] "IsWord" [TLName typeCtor] $ [ iValue "fromWord" [PVar "n"] $ ECase (ETypeAnno (EApp (eStd_ "fromIntegral") [euName "n"]) (TPrim $ C.PrimInt $ C.IntType C.Unsigned C.Sz16) ) $ [ (PInt i, ELName ctor) | (i, ctor) <- zip [0..] dataCtors] ++ [ (PVar "tag", EApp (ELName unknownCtor) [euName "tag"]) ] ] ++ [ IdValue $ DfValue { name = "toWord" , params = [PLCtor ctor []] , value = EInt i } | (i, ctor) <- zip [0..] dataCtors ] ++ [ IdValue $ DfValue { name = "toWord" , params = [ PLCtor unknownCtor [PVar "tag"] ] , value = EApp (eStd_ "fromIntegral") [ELName "tag"] } ] newtypeWrapper :: Name.LocalQ -> [T.Text] -> Type -> Decl newtypeWrapper typeCtor typeArgs wrappedType = DcData Data { dataName = Name.localToUnQ typeCtor , dataNewtype = True , typeArgs = map TVar typeArgs , dataVariants = [ DataVariant { dvCtorName = Name.localToUnQ $ Name.mkSub typeCtor "newtype_" , dvArgs = APos [ wrappedType ] } ] , derives = [] } wrapperFromPtr :: Name.LocalQ -> Name.LocalQ -> Decl wrapperFromPtr typeCtor dataCtor = instance_ [] ["Classes"] "FromPtr" [ TVar "msg", TApp (TLName typeCtor) [TVar "msg"] ] [ iValue "fromPtr" [PVar "msg", PVar "ptr"] $ EFApp (ELName dataCtor) [ EApp (egName ["Classes"] "fromPtr") [ ELName "msg" , ELName "ptr" ] ] ] nameToType :: Word64 -> Name.CapnpQ -> Type nameToType thisMod Name.CapnpQ{local, fileId} = if fileId == thisMod then TLName local else tgName (map Name.renderUnQ $ idToModule fileId) local typeToType :: Word64 -> C.Type Name.CapnpQ -> Type -> Type typeToType thisMod ty msgTy = case ty of C.VoidType -> TUnit C.WordType (C.PrimWord ty) -> TPrim ty C.WordType (C.EnumType typeId) -> nameToType thisMod typeId C.PtrType (C.ListOf elt) -> TApp (tgName ["Basics"] "List") [ msgTy , typeToType thisMod elt msgTy ] C.PtrType (C.PrimPtr C.PrimText) -> appV $ tgName ["Basics"] "Text" C.PtrType (C.PrimPtr C.PrimData) -> appV $ tgName ["Basics"] "Data" C.PtrType (C.PtrComposite (C.StructType typeId)) -> appV $ nameToType thisMod typeId C.PtrType (C.PtrInterface typeId) -> appV $ nameToType thisMod typeId C.PtrType (C.PrimPtr (C.PrimAnyPtr _)) -> TApp (tStd_ "Maybe") [appV $ tgName ["Untyped"] "Ptr"] C.CompositeType (C.StructType typeId) -> appV $ nameToType thisMod typeId where appV t = TApp t [msgTy]