packages feed

candid 0.4.0.2 → 0.5

raw patch · 14 files changed

+153/−85 lines, 14 filesdep +digestdep −crcdep ~basedep ~base32dep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: digest

Dependencies removed: crc

Dependency ranges changed: base, base32, bytestring, cereal, constraints, containers, directory, doctest, file-embed, filepath, hex-text, megaparsec, optparse-applicative, row-types, scientific, split, tasty, tasty-hunit, template-haskell, text, transformers, unordered-containers, vector

API changes (from Hackage documentation)

+ Codec.Candid: RepeatV :: Int -> Value -> Value
+ Codec.Candid: [methCompQuery] :: MethodType a -> Bool
- Codec.Candid: FuncRef :: Principal -> Text -> FuncRef r
+ Codec.Candid: FuncRef :: Principal -> Text -> FuncRef (r :: Type)
- Codec.Candid: MethodType :: [Type a] -> [Type a] -> Bool -> Bool -> MethodType a
+ Codec.Candid: MethodType :: [Type a] -> [Type a] -> Bool -> Bool -> Bool -> MethodType a
- Codec.Candid: [method] :: FuncRef r -> Text
+ Codec.Candid: [method] :: FuncRef (r :: Type) -> Text
- Codec.Candid: [service] :: FuncRef r -> Principal
+ Codec.Candid: [service] :: FuncRef (r :: Type) -> Principal
- Codec.Candid: data FuncRef r
+ Codec.Candid: data FuncRef (r :: Type)

Files

CHANGELOG.md view
@@ -1,9 +1,20 @@ # Revision history for haskell-candid +## 0.5 -- 2023-10-17++* GHC-9.8 compatibility+* Support spec version 0.1.6:+  - `composite_query`+    https://github.com/dfinity/candid/pull/420+  - `record {} <: record {null}`+    https://github.com/dfinity/candid/pull/462+  - space bomb protection+    https://github.com/dfinity/candid/pull/434+ ## 0.4.0.2 -- 2023-06-03  * Bump dependencies-* GHC-9.t+* GHC-9.6  ## 0.4.0.1 -- 2023-01-01 
candid.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.0 name:               candid-version:            0.4.0.2+version:            0.5 license:            Apache license-file:       LICENSE maintainer:         mail@joachim-breitner.de@@ -47,41 +47,41 @@     default-language: Haskell2010     ghc-options:      -Wall -Wno-name-shadowing     build-depends:-        base ^>=4.14.3.0 || ^>=4.15.1.0 || ^>=4.16.3.0 || ^>=4.17.0.0 || ^>=4.18.0.0,-        text ^>=1.2.4.1 || ^>=2.0.1,+        base ^>=4.14.3 || ^>=4.15.1 || ^>=4.16.3 || ^>=4.17.0 || ^>=4.18.1 || ^>=4.19.0,+        text ^>=1.2.4 || ^>=2.0.1 || ^>=2.1,         dlist ^>=1.0,-        vector ^>=0.12.3.1 || ^>=0.13.0.0,-        bytestring ^>=0.10.12.0 || ^>=0.11.3.1,+        vector ^>=0.12.3 || ^>=0.13.0,+        bytestring ^>=0.10.12 || ^>=0.11.3 || ^>=0.12.0,         mtl ^>=2.2.2 || ^>=2.3.1,-        transformers ^>=0.5.6.2 || ^>=0.6.1.0,-        hex-text ^>=0.1.0.7,-        crc ^>=0.1.1.1,-        megaparsec ^>=9.2.1 || ^>=9.3.1,+        transformers ^>=0.5.6 || ^>=0.6.1,+        hex-text ^>=0.1.0,+        digest ^>=0.0.1,+        megaparsec ^>=9.2.1 || ^>=9.3.1 || ^>=9.4.1 || ^>=9.5.0,         parser-combinators ^>=1.3.0,-        scientific ^>=0.3.7.0,-        cereal ^>=0.5.8.3,+        scientific ^>=0.3.7,+        cereal ^>=0.5.8,         leb128-cereal ^>=1.2,-        containers ^>=0.6.4.1,-        unordered-containers ^>=0.2.19.1,-        row-types ^>=1.0.1.2,-        constraints ^>=0.13.4,+        containers ^>=0.6.4,+        unordered-containers ^>=0.2.19,+        row-types ^>=1.0.1,+        constraints ^>=0.13.4 || ^>=0.14,         prettyprinter ^>=1.7.1,-        template-haskell ^>=2.16.0.0 || ^>=2.17.0.0 || ^>=2.18.0.0 || ^>=2.19.0.0 || ^>=2.20.0.0,-        base32 ^>=0.2.2.0 || ^>=0.3.1.0,-        split ^>=0.2.3.5,-        file-embed ^>=0.0.15.0+        template-haskell ^>=2.16.0 || ^>=2.17.0 || ^>=2.18.0 || ^>=2.19.0 || ^>=2.20.0 || ^>=2.21.0,+        base32 ^>=0.2.2 || ^>=0.3.1,+        split ^>=0.2.3,+        file-embed ^>=0.0.15  executable hcandid     main-is:          hcandid.hs     default-language: Haskell2010     ghc-options:      -Wall -Wno-name-shadowing     build-depends:-        base ^>=4.14.3.0 || ^>=4.15.1.0 || ^>=4.16.3.0 || ^>=4.17.0.0 || ^>=4.18.0.0,+        base ^>=4.14.3 || ^>=4.15.1 || ^>=4.16.3 || ^>=4.17.0 || ^>=4.18.1 || ^>=4.19.0,         candid,-        optparse-applicative ^>=0.17.0.0 || ^>=0.18.1.0,-        text ^>=1.2.4.1 || ^>=2.0.1,-        bytestring ^>=0.10.12.0 || ^>=0.11.3.1,-        hex-text ^>=0.1.0.7,+        optparse-applicative ^>=0.17.1 || ^>=0.18.1,+        text ^>=1.2.4 || ^>=2.0.1 || ^>=2.1,+        bytestring ^>=0.10.12 || ^>=0.11.3 || ^>=0.12.0,+        hex-text ^>=0.1.0,         prettyprinter ^>=1.7.1  test-suite test@@ -96,23 +96,23 @@     default-language: Haskell2010     ghc-options:      -Wall -Wno-name-shadowing -rtsopts     build-depends:-        base ^>=4.14.3.0 || ^>=4.15.1.0 || ^>=4.16.3.0 || ^>=4.17.0.0 || ^>=4.18.0.0,-        tasty ^>=1.4.3,-        tasty-hunit ^>=0.10.0.3,+        base ^>=4.14.3 || ^>=4.15.1 || ^>=4.16.3 || ^>=4.17.0 || ^>=4.18.1 || ^>=4.19.0,+        tasty ^>=1.4.3 || ^>=1.5,+        tasty-hunit ^>=0.10.0,         tasty-smallcheck ^>=0.8.2,         tasty-quickcheck ^>=0.10.2,         tasty-rerun ^>=1.1.18,         smallcheck ^>=1.2.1,         candid,-        bytestring ^>=0.10.12.0 || ^>=0.11.3.1,-        text ^>=1.2.4.1 || ^>=2.0.1,-        vector ^>=0.12.3.1 || ^>=0.13.0.0,+        bytestring ^>=0.10.12 || ^>=0.11.3 || ^>=0.12.0,+        text ^>=1.2.4 || ^>=2.0.1 || ^>=2.1,+        vector ^>=0.12.3 || ^>=0.13.0,         prettyprinter ^>=1.7.1,-        unordered-containers ^>=0.2.19.1,-        row-types ^>=1.0.1.2,-        directory ^>=1.3.6.0,-        filepath ^>=1.4.2.1,-        template-haskell ^>=2.16.0.0 || ^>=2.17.0.0 || ^>=2.18.0.0 || ^>=2.19.0.0 || ^>=2.20.0.0+        unordered-containers ^>=0.2.19,+        row-types ^>=1.0.1,+        directory ^>=1.3.6,+        filepath ^>=1.4.2,+        template-haskell ^>=2.16.0 || ^>=2.17.0 || ^>=2.18.0 || ^>=2.19.0 || ^>=2.20.0 || ^>=2.21.0  test-suite doctest     type:             exitcode-stdio-1.0@@ -120,10 +120,10 @@     default-language: Haskell2010     ghc-options:      -threaded     build-depends:-        base ^>=4.14.3.0 || ^>=4.15.1.0 || ^>=4.16.3.0 || ^>=4.17.0.0 || ^>=4.18.0.0,+        base ^>=4.14.3 || ^>=4.15.1 || ^>=4.16.3 || ^>=4.17.0 || ^>=4.18.1 || ^>=4.19.0,         candid,-        doctest ^>=0.20.1 || ^>=0.21.1,-        row-types ^>=1.0.1.2,+        doctest ^>=0.20.1 || ^>=0.21.1 || ^>=0.22.2,+        row-types ^>=1.0.1,         leb128-cereal ^>=1.2,         prettyprinter ^>=1.7.1 
src/Codec/Candid/Class.hs view
@@ -379,6 +379,7 @@ instance Candid a => CandidVal (Vec.Vector a) where     asType = VecT (asType' @a)     toCandidVal' = VecV . fmap toCandidVal+    fromCandidVal' (RepeatV n x) = Vec.replicate n <$> fromCandidVal'' x     fromCandidVal' (VecV x) = traverse fromCandidVal'' x     fromCandidVal' (BlobV b) = traverse (fromCandidVal'' . Nat8V) $ Vec.fromList $ BS.unpack b     fromCandidVal' v = cannotCoerce "vec" v@@ -416,8 +417,8 @@ class Typeable a => CandidMethodType a where     asMethodType :: MethodType (Ref TypeRep Type) -instance (CandidArg a, CandidArg b, KnownAnnotation q, KnownAnnotation o) => CandidMethodType (a, b, q, o) where-    asMethodType = MethodType (asTypes @(AsTuple a)) (asTypes @(AsTuple b)) (isTrue @q) (isTrue @o)+instance (CandidArg a, CandidArg b, KnownAnnotation q, KnownAnnotation cq, KnownAnnotation o) => CandidMethodType (a, b, q, cq, o) where+    asMethodType = MethodType (asTypes @(AsTuple a)) (asTypes @(AsTuple b)) (isTrue @q) (isTrue @cq) (isTrue @o)  methodsOfRow :: forall r. Forall r CandidMethodType => [(T.Text, MethodType (Ref TypeRep Type))] methodsOfRow = getConst $ metamorph @_ @r @CandidMethodType @(,) @(Const ()) @(Const [(T.Text, MethodType (Ref TypeRep Type))]) @Proxy Proxy doNil doUncons doCons (Const ())
src/Codec/Candid/Coerce.hs view
@@ -100,6 +100,7 @@ go v EmptyT _ = throwError $ show $ "Unexpected value" <+> pretty v <+> "while coercing empty"  -- vec t1 <: vec t2+go (RepeatV n v) (VecT t1) (VecT t2) = RepeatV n <$> go v t1 t2 go (VecV vs) (VecT t1) (VecT t2) = VecV <$> mapM (\v -> go v t1 t2) vs  -- Option: The normal rule@@ -130,7 +131,8 @@       case (M.lookup fn vm, M.lookup fn m1) of         (Just v, Just t1) -> go v t1 t2         _ -> case unRef t2 of-            OptT _ -> pure (OptV Nothing)+            NullT     -> pure NullV+            OptT _    -> pure (OptV Nothing)             ReservedT -> pure ReservedV             t -> throwError $ show $ "Missing record field" <+> pretty fn <+> "of type" <+> pretty t @@ -159,6 +161,7 @@  goSeq _ _ []  = pure [] goSeq vs ts1 (RefT (Ref _ t) : ts) = goSeq vs ts1 (t:ts)+goSeq vs@[] ts1@[] (NullT     : ts) = (NullV :)        <$> goSeq vs ts1 ts goSeq vs@[] ts1@[] (OptT _    : ts) = (OptV Nothing :) <$> goSeq vs ts1 ts goSeq vs@[] ts1@[] (ReservedT : ts) = (ReservedV :)    <$> goSeq vs ts1 ts goSeq [] [] ts = throwError $ show $ "Argument type list too short, expecting types" <+> pretty ts
src/Codec/Candid/Data.hs view
@@ -10,7 +10,6 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Row.Internal as R-import Data.Digest.CRC import Data.Digest.CRC32 import Data.ByteString.Base32 import Data.List@@ -29,7 +28,7 @@ prettyPrincipal (Principal blob) =     T.pack $ intercalate "-" $ chunksOf 5 $ base32 $ checkbytes <> blob   where-    CRC32 checksum = digest (BS.toStrict blob)+    checksum = crc32 (BS.toStrict blob)     checkbytes = BS.toLazyByteString (BS.word32BE checksum)     base32 = filter (/='=') . T.unpack . T.toLower . encodeBase32 . BS.toStrict @@ -48,6 +47,6 @@ newtype ServiceRef (r :: R.Row Type) = ServiceRef { rawServiceRef :: Principal }  deriving (Eq, Ord, Show) -data FuncRef r = FuncRef { service :: Principal, method :: T.Text }+data FuncRef (r :: Type) = FuncRef { service :: Principal, method :: T.Text }  deriving (Eq, Ord, Show) 
src/Codec/Candid/Decode.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE NumericUnderscores #-}  module Codec.Candid.Decode where @@ -31,6 +32,9 @@         decodeMagic         arg_tys <- decodeTypTable         vs <- mapM decodeVal (tieKnot (voidEmptyTypes arg_tys))+        let n = sum (countZeroSizeVectors <$> vs)+        when (n > 2_000_000) $ do+            fail $ "Message contains " ++ show n ++ " zero sized values in a vector, exceeding the limit of 2_000_000"         G.remaining >>= \case             0 -> return (arg_tys, vs)             n -> fail $ "Unexpected " ++ show n ++ " left-over bytes"@@ -62,7 +66,9 @@ decodeVal BlobT = BlobV <$> decodeBytes decodeVal (VecT t) = do     n <- getLEB128Int-    VecV . V.fromList <$> replicateM n (decodeVal t)+    case decodeZeroBytes t of+        Just v ->pure $ RepeatV n v+        Nothing -> VecV . V.fromList <$> replicateM n (decodeVal t) decodeVal (RecT fs)     | isTuple   = TupV <$> mapM (\(_,t) -> decodeVal t) fs'     | otherwise = RecV <$> mapM (\(fn, t) -> (fn,) <$> decodeVal t) fs'@@ -167,7 +173,7 @@     -22 -> do         a <- decodeSeq (decodeTypRef max)         r <- decodeSeq (decodeTypRef max)-        m <- decodeFoldSeq decodeFuncAnn (MethodType a r False False)+        m <- decodeFoldSeq decodeFuncAnn (MethodType a r False False False)         return $ Left (FuncT m)     -23 -> do         m <- decodeSeq ((,) <$> decodeText <*> decodeFuncTypRef max)@@ -220,6 +226,9 @@     2 -> do         when (methOneway m) $ fail "oneway annotation duplicated"         return (m { methOneway = True })+    3 -> do+        when (methCompQuery m) $ fail "composite_query annotation duplicated"+        return (m { methCompQuery = True })     _ -> fail "invalid function annotation"  @@ -240,3 +249,31 @@     h <- getLEB128     t <- decodeTypRef max     return (hashedField h, t)++decodeZeroBytes :: Type a -> Maybe Value+decodeZeroBytes ReservedT = Just ReservedV+decodeZeroBytes NullT = Just NullV+decodeZeroBytes (RecT fs) = RecV <$> mapM (\(fn, t) -> (fn,) <$> decodeZeroBytes t) fs'+  where+    fs' = sortOn fst fs+decodeZeroBytes _ = Nothing++{-+isZeroSizedValue :: Value -> Bool+isZeroSizedValue ReservedV = True+isZeroSizedValue NullV = True+isZeroSizedValue (RecV fs) = all (isZeroSizedValue . snd) fs+isZeroSizedValue (TupV vs) = all isZeroSizedValue vs+isZeroSizedValue _ = False+-}++countZeroSizeVectors :: Value -> Int+countZeroSizeVectors (RepeatV n _) = n+countZeroSizeVectors (VecV vs) = sum (countZeroSizeVectors <$> vs)+countZeroSizeVectors (RecV fs) = sum (countZeroSizeVectors . snd <$> fs)+countZeroSizeVectors (TupV vs) = sum (countZeroSizeVectors <$> vs)+countZeroSizeVectors (VariantV _ v) = countZeroSizeVectors v+countZeroSizeVectors (OptV (Just v)) = countZeroSizeVectors v+countZeroSizeVectors (AnnV v _) = countZeroSizeVectors v+countZeroSizeVectors _ = 0+
src/Codec/Candid/Encode.hs view
@@ -195,7 +195,7 @@        RefT t -> go (m M.! t) -    goMethod (MethodType as bs q o) = do+    goMethod (MethodType as bs q cq o) = do         ais <- mapM go as         bis <- mapM go bs         return $ mconcat@@ -209,7 +209,8 @@           ]       where         anns = [buildLEB128 @Natural 1 | q] ++-               [buildLEB128 @Natural 2 | o]+               [buildLEB128 @Natural 2 | o] +++               [buildLEB128 @Natural 3 | cq]      goField :: (FieldName, Type k) -> TypTableBuilder k (FieldName, Integer)     goField (fn, t) = do
src/Codec/Candid/Hash.hs view
@@ -58,7 +58,7 @@  -- Word list obtained from https://github.com/dwyl/english-words wordFile :: T.Text-wordFile = $(embedStringFile "words.txt")+wordFile = $(makeRelativeToProject "words.txt" >>= embedStringFile)  m :: M.IntMap T.Text m = M.fromList [ (fromIntegral (candidHash w), w) | w <- word_list ]
src/Codec/Candid/Infer.hs view
@@ -33,13 +33,14 @@ inferTyp ReservedV = return ReservedT inferTyp (OptV Nothing) = return $ OptT EmptyT inferTyp (OptV (Just v)) = OptT <$> inferTyp v+inferTyp (RepeatV _ v) = VecT <$> inferTyp v inferTyp (VecV vs) = VecT <$> (mapM inferTyp (V.toList vs) >>= lubs) inferTyp (RecV fs) = RecT <$> sequence [ (fn,) <$> inferTyp t | (fn, t) <- fs ] inferTyp (VariantV f v) = do     t <- inferTyp v     return $ VariantT [ (f, t) ] inferTyp (TupV vs) = tupT <$> mapM inferTyp vs-inferTyp (FuncV _ _) = return (FuncT (MethodType [] [] False False)) -- no principal type+inferTyp (FuncV _ _) = return (FuncT (MethodType [] [] False False False)) -- no principal type inferTyp (ServiceV _) = return (ServiceT []) -- no principal type inferTyp (PrincipalV _) = return PrincipalT inferTyp FutureV = return FutureT
src/Codec/Candid/Parse.hs view
@@ -91,10 +91,11 @@     ts1 <- seqP     s "->"     ts2 <- seqP-    (q,o) <- runPermutation $-         (,) <$> toPermutationWithDefault False (True <$ s "query")-             <*> toPermutationWithDefault False (True <$ s "oneway")-    return $ MethodType ts1 ts2 q o+    (q,cq,o) <- runPermutation $+         (,,) <$> toPermutationWithDefault False (True <$ s "query")+              <*> toPermutationWithDefault False (True <$ s "composite_query")+              <*> toPermutationWithDefault False (True <$ s "oneway")+    return $ MethodType ts1 ts2 q cq o  nameP :: Parser T.Text nameP = textP <|> idP <?> "name"
src/Codec/Candid/Subtype.hs view
@@ -122,7 +122,8 @@     -- Check missing fields     sequence_       [ case unRef t of-          OptT _ -> pure ()+          NullT     -> pure ()+          OptT _    -> pure ()           ReservedT -> pure ()           t -> throwError $ show $ "Missing record field" <+> pretty fn <+> "of type" <+> pretty t       | (fn, t) <- M.toList $ m2 M.\\ m1@@ -162,16 +163,18 @@     MethodType (Ref k1 Type) ->     MethodType (Ref k2 Type) ->     SubTypeM k1 k2 ()-goMethodType (MethodType ta1 tr1 q1 o1) (MethodType ta2 tr2 q2 o2) = do+goMethodType (MethodType ta1 tr1 q1 cq1 o1) (MethodType ta2 tr2 q2 cq2 o2) = do     unless (q1 == q2) $ throwError "Methods differ in query annotation"     unless (o1 == o2) $ throwError "Methods differ in oneway annotation"+    unless (cq1 == cq2) $ throwError "Methods differ in oneway annotation"     flipM $ goSeq ta2 ta1     goSeq tr1 tr2  goSeq _ []  = pure () goSeq ts1 (RefT (Ref _ t) : ts) = goSeq ts1 (t:ts) -- Missing optional arguments are ok-goSeq ts1@[] (OptT _ : ts) = goSeq ts1 ts+goSeq ts1@[] (NullT : ts)     = goSeq ts1 ts+goSeq ts1@[] (OptT _ : ts)    = goSeq ts1 ts goSeq ts1@[] (ReservedT : ts) = goSeq ts1 ts goSeq [] ts = throwError $ show $ "Argument type list too short, expecting types" <+> pretty ts goSeq (t1:ts1) (t2:ts2) = memo t1 t2 >> goSeq ts1 ts2
src/Codec/Candid/TH.hs view
@@ -195,8 +195,8 @@     methodName f = litT (strTyLit (T.unpack f))  methodType :: MethodType TH.Name -> TypeQ-methodType (MethodType a b q o) =-    [t| ($(candidTypeQ a), $(candidTypeQ b), $(ann q), $(ann o)) |]+methodType (MethodType a b q cq o) =+    [t| ($(candidTypeQ a), $(candidTypeQ b), $(ann q), $(ann cq), $(ann o)) |]   where     ann True = [t|AnnTrue|]     ann False = [t|AnnFalse|]
src/Codec/Candid/Types.hs view
@@ -86,8 +86,8 @@     RefT x >>= f = f x  bindMethodType :: (a -> Type b) -> MethodType a -> MethodType b-bindMethodType f (MethodType as bs q ow) =-   MethodType (map (>>= f) as) (map (>>= f) bs) q ow+bindMethodType f (MethodType as bs q cq ow) =+   MethodType (map (>>= f) as) (map (>>= f) bs) q cq ow   type Fields a = [(FieldName, Type a)]@@ -155,6 +155,7 @@   | NullV   | ReservedV   | OptV (Maybe Value)+  | RepeatV Int Value -- for space bomb protection   | VecV (V.Vector Value)   | RecV [(FieldName, Value)]   | TupV [Value]@@ -193,6 +194,9 @@   pretty (BlobV b) = "blob" <+> prettyBlob b   pretty (OptV Nothing) = pretty NullV   pretty (OptV (Just v)) = "opt" <+> pretty v+  pretty (RepeatV n v)+    | n < 20 = pretty (VecV (V.replicate n v))+    | otherwise = "vec" <+> prettyBraceSemi [pretty v, "…"]   pretty (VecV vs) = "vec" <+> prettyBraceSemi (map pretty (V.toList vs))   pretty (TupV vs) = "record" <+> prettyBraceSemi (map pretty vs)   pretty (RecV vs) = "record" <+> prettyBraceSemi (map go vs)@@ -263,6 +267,7 @@     { methParams :: [Type a]     , methResults :: [Type a]     , methQuery :: Bool+    , methCompQuery :: Bool     , methOneway :: Bool     }   deriving (Eq, Ord, Show, Functor, Foldable, Traversable)@@ -276,12 +281,13 @@   deriving (Eq, Show)  instance Pretty a => Pretty (MethodType a) where-  pretty (MethodType params results q o) = sep $+  pretty (MethodType params results q cq o) = sep $       [ pretty params       , "->"       , pretty results       ] <>       [ "query" | q ] <>+      [ "composite_query" | cq ] <>       [ "oneway" | o ]  prettyDef :: Pretty a => DidDef a -> Doc ann
test/Tests.hs view
@@ -200,9 +200,9 @@     , mkTest (Proxy @SimpleRecord)     , mkTest (Proxy @(Rec ("a" .== Bool .+ "b" .== Bool .+ "c" .== Bool)))     , mkTest (Proxy @(V.Var ("upgrade" .== () .+ "reinstall" .== () .+ "install" .== ())))-    , mkTest (Proxy @(FuncRef (Bool, T.Text, AnnFalse, AnnFalse)))-    , mkTest (Proxy @(FuncRef (Bool, T.Text, AnnTrue, AnnFalse)))-    , mkTest (Proxy @(FuncRef (Bool, T.Text, AnnFalse, AnnTrue)))+    , mkTest (Proxy @(FuncRef (Bool, T.Text, AnnFalse, AnnFalse, AnnFalse)))+    , mkTest (Proxy @(FuncRef (Bool, T.Text, AnnTrue,  AnnFalse, AnnFalse)))+    , mkTest (Proxy @(FuncRef (Bool, T.Text, AnnFalse, AnnFalse, AnnTrue)))     , mkTest (Proxy @(ServiceRef Empty))     ] @@ -286,10 +286,11 @@     , printTestType @Word8 "nat8"     , printTestType @SimpleRecord "record {bar : nat8; foo : bool}"     , printTestType @(JustRight T.Text) "variant {Right : text}"-    , printTestType @(FuncRef (Bool, Unary (), AnnTrue, AnnFalse)) "func (bool) -> (null) query"-    , printTestType @(FuncRef (Bool, T.Text, AnnFalse, AnnTrue)) "func (bool) -> (text) oneway"+    , printTestType @(FuncRef (Bool, Unary (), AnnTrue, AnnFalse, AnnFalse)) "func (bool) -> (null) query"+    , printTestType @(FuncRef (Bool, T.Text, AnnFalse, AnnFalse, AnnTrue)) "func (bool) -> (text) oneway"+    , printTestType @(FuncRef (Bool, T.Text, AnnFalse, AnnTrue, AnnFalse)) "func (bool) -> (text) composite_query"     , printTestType @(ServiceRef Empty) "service : {}"-    , printTestType @(ServiceRef ("foo" .== (Bool, T.Text, AnnFalse, AnnTrue) .+ "bar" .== ((),(),AnnFalse, AnnFalse)))+    , printTestType @(ServiceRef ("foo" .== (Bool, T.Text, AnnFalse, AnnFalse, AnnTrue) .+ "bar" .== ((),(),AnnFalse, AnnFalse, AnnFalse)))         "service : {bar : () -> (); foo : (bool) -> (text) oneway;}"     , printTestSeq @() "()"     , printTestSeq @(Unary ()) "(null)"@@ -364,11 +365,11 @@     , t "blob \"hello\"" ("hello" :: BS.ByteString)     , t "blob \"\\00\\ff\"" ("\x00\xff" :: BS.ByteString)     , t "func \"psokg-ww6vw-7o6\".\"foo\""-        (FuncRef @((), (), AnnFalse, AnnFalse) (Principal "\xde\xad\xbe\xef") "foo")+        (FuncRef @((), (), AnnFalse, AnnFalse, AnnFalse) (Principal "\xde\xad\xbe\xef") "foo")     , t "func \"psokg-ww6vw-7o6\".foo"-        (FuncRef @((), (), AnnFalse, AnnFalse) (Principal "\xde\xad\xbe\xef") "foo")+        (FuncRef @((), (), AnnFalse, AnnFalse, AnnFalse) (Principal "\xde\xad\xbe\xef") "foo")     , t "func \"psokg-ww6vw-7o6\".\"\""-        (FuncRef @((), (), AnnFalse, AnnFalse) (Principal "\xde\xad\xbe\xef") "")+        (FuncRef @((), (), AnnFalse, AnnFalse, AnnFalse) (Principal "\xde\xad\xbe\xef") "")     , t "service \"psokg-ww6vw-7o6\""         (ServiceRef @Empty (Principal "\xde\xad\xbe\xef"))     , t "principal \"psokg-ww6vw-7o6\""@@ -381,31 +382,35 @@     [ parseTest "service : {}" $       DidFile [] []     , parseTest "service : { foo : (text) -> (text) }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] False False)]+      DidFile [] [("foo", MethodType [TextT] [TextT] False False False)]     , parseTest "service : { foo : (text,) -> (text,); }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] False False)]+      DidFile [] [("foo", MethodType [TextT] [TextT] False False False)]     , parseTest "service : { foo : (x : text,) -> (y : text,); }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] False False)]+      DidFile [] [("foo", MethodType [TextT] [TextT] False False False)]     , parseTest "service : { foo : (opt text) -> () }" $-      DidFile [] [("foo", MethodType [OptT TextT] [] False False) ]+      DidFile [] [("foo", MethodType [OptT TextT] [] False False False) ]     , parseTest "service : { foo : (record { text; blob }) -> () }" $-      DidFile [] [("foo", MethodType [RecT [(hashedField 0, TextT), (hashedField 1, BlobT)]] [] False False) ]+      DidFile [] [("foo", MethodType [RecT [(hashedField 0, TextT), (hashedField 1, BlobT)]] [] False False False) ]     , parseTest "service : { foo : (record { x_ : null; 5 : nat8 }) -> () }" $-      DidFile [] [("foo", MethodType [RecT [("x_", NullT), (hashedField 5, Nat8T)]] [] False False) ]+      DidFile [] [("foo", MethodType [RecT [("x_", NullT), (hashedField 5, Nat8T)]] [] False False False) ]     , parseTest "service : { foo : (record { x : null; 5 : nat8 }) -> () }" $-      DidFile [] [("foo", MethodType [RecT [("x", NullT), (hashedField 5, Nat8T)]] [] False False) ]+      DidFile [] [("foo", MethodType [RecT [("x", NullT), (hashedField 5, Nat8T)]] [] False False False) ]     , parseTest "service : { foo : (text) -> (text) query }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] True False)]+      DidFile [] [("foo", MethodType [TextT] [TextT] True False False)]     , parseTest "service : { foo : (text) -> (text) oneway }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] False True)]+      DidFile [] [("foo", MethodType [TextT] [TextT] False False True)]+    , parseTest "service : { foo : (text) -> (text) composite_query }" $+      DidFile [] [("foo", MethodType [TextT] [TextT] False True False)]     , parseTest "service : { foo : (text) -> (text) query oneway }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] True True)]+      DidFile [] [("foo", MethodType [TextT] [TextT] True False True)]     , parseTest "service : { foo : (text) -> (text) oneway query }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] True True)]+      DidFile [] [("foo", MethodType [TextT] [TextT] True False True)]+    , parseTest "service : { foo : (text) -> (text) oneway composite_query }" $+      DidFile [] [("foo", MethodType [TextT] [TextT] False True True)]     , parseTest "service : (opt SomeInit) -> { foo : (text) -> (text) oneway query }" $-      DidFile [] [("foo", MethodType [TextT] [TextT] True True)]+      DidFile [] [("foo", MethodType [TextT] [TextT] True False True)]     , parseTest "type t = int; service : { foo : (t) -> (t) }" $-      DidFile [("t", IntT)] [("foo", MethodType [RefT "t"] [RefT "t"] False False)]+      DidFile [("t", IntT)] [("foo", MethodType [RefT "t"] [RefT "t"] False False False)]     ]   , testProperty "field name escaping round-tripping" $ \e ->       let f = either labledField hashedField e in