packages feed

morley 1.7.1 → 1.8.0

raw patch · 47 files changed

+1244/−898 lines, 47 filesdep −QuickCheckdep −quickcheck-arbitrary-adtdep −quickcheck-instances

Dependencies removed: QuickCheck, quickcheck-arbitrary-adt, quickcheck-instances

Files

CHANGES.md view
@@ -1,3 +1,24 @@+1.8.0+=====++* [!610](https://gitlab.com/morley-framework/morley/-/merge_requests/610)+  Remove `Arbitrary` instances and everything else that depends on `QuickCheck`.+* [!616](https://gitlab.com/morley-framework/morley/-/merge_requests/616)+  Make `RootAnn` a mere type alias of `FieldAnn`.+* [!615](https://gitlab.com/morley-framework/morley/-/merge_requests/615)+  Make `mkEntrypointsMap` accept `ParameterType` instead of `Type`.+* [!567](https://gitlab.com/morley-framework/morley/-/merge_requests/567)+  Add `DConversionInfo` that describes Haskell <-> Michelson conversion+  mechanism.+* [!585](https://gitlab.com/morley-framework/morley/-/merge_requests/585)+  Add `Exception` instance for `ParseChainIdError`.+* [!598](https://gitlab.com/morley-framework/morley/-/merge_requests/598)+  Fix bug: correct processing of `EDIV` of negative `Integer` and `Natural`.+* [!574](https://gitlab.com/morley-framework/morley/-/merge_requests/574)+  Implement a verbose switch for `morley typecheck`. It allows to+  print a stack type after every well-typed instruction, even if a+  contract as a whole is ill-typed.+ 1.7.1 ===== * [!549](https://gitlab.com/morley-framework/morley/-/merge_requests/549)
app/Main.hs view
@@ -6,6 +6,7 @@   ( main   ) where +import Data.Default (def) import qualified Data.Text.Lazy.IO.Utf8 as Utf8 (writeFile) import Data.Version (showVersion) import Fmt (pretty)@@ -26,7 +27,7 @@ import Michelson.Runtime   (TxData(..), originateContract, prepareContract, readAndParseContract, runContract, transfer) import Michelson.Runtime.GState (genesisAddress)-import Michelson.TypeCheck (typeCheckContract)+import Michelson.TypeCheck (tcVerbose, typeCheckContract) import Michelson.TypeCheck.Types (SomeContract(..), mapSomeContract) import Michelson.Typed (Contract(..)) import qualified Michelson.Untyped as U@@ -287,17 +288,21 @@         write $ printUntypedContract forceSingleLine contract       Optimize OptimizeOptions{..} -> do         untypedContract <- prepareContract optoContractFile-        checkedContract <- either throwM pure $ typeCheckContract untypedContract+        checkedContract <-+          either throwM pure $ typeCheckContract untypedContract def         let optimizedContract = mapSomeContract optimize checkedContract         let write = maybe putStrLn Utf8.writeFile optoOutput         write $ printSomeContract optoSingleLine optimizedContract       Analyze AnalyzeOptions{..} -> do         untypedContract <- prepareContract aoContractFile-        SomeContract contract <- either throwM pure $ typeCheckContract untypedContract+        SomeContract contract <-+          either throwM pure $ typeCheckContract untypedContract def         putTextLn $ pretty $ analyze (cCode contract)       TypeCheck TypeCheckOptions{..} -> do         morleyContract <- prepareContract tcoContractFile-        either throwM (const pass) $ typeCheckContract morleyContract+        contract <- either throwM pure+          $ typeCheckContract morleyContract def{ tcVerbose = tcoVerbose }+        when tcoVerbose (putStrLn $ printSomeContract False contract)         putTextLn "Contract is well-typed"       Run RunOptions {..} -> do         michelsonContract <- prepareContract roContractFile
app/REPL.hs view
@@ -230,7 +230,7 @@   T.Dict -> case T.checkOpPresence (T.sing @a) of     T.OpAbsent -> -- print nice if value has no operations       addSuffix (toText $ printTypedValue True v)-    T.OpPresent -> -- else just call show, and indicate value has operation inside+    _ ->          -- else just call show, and indicate value has operation inside       case (v, T.sing @a) of         (T.VList [], T.STList T.STOperation) -> "{ } :: list operation\n" <> showStack rst rHst         _ -> addSuffix $ "(operations container:" <> show v <> ")"
docs/language/morleyInstructions.md view
@@ -71,6 +71,6 @@        PUSH int 2;        PUSH int 10;        TEST_ASSERT Test1 "%[0] + %[1] > 10" {ADD; PUSH int 10; COMPARE;LT;};-       DROP; UNIT; NIL operation; PAIR; };+       DROP; DROP; UNIT; NIL operation; PAIR; };  ```
docs/morleyTypechecker.md view
@@ -6,26 +6,43 @@  # Morley Typechecker -In Morley, we have a typechecker for the core Michelson language, i. e. without macros.-It is located in `Michelson.TypeCheck` and designed in the following way:-* It takes a core Michelson contract extended with `EXT` instruction to support additional instructions described in the [`morleyInstructions.md`](language/morleyInstructions.md) document.-* The contract passed to the typechecker uses [untyped representation](./michelsonTypes.md).-* During typechecking, we verify that instructions are well-typed and provide evidence to the compiler that allows us to convert instructions into [typed representation](./michelsonTypes.md). If the contract is ill-typed, the typechecking process fails with an error.-* The typechecker can check a whole contract or a standalone value (for example, a lambda).-In the former case it needs to know the parameter type of the contract (to check `SELF`).+In Morley, we have a typechecker for the core Michelson language,+i. e. without macros.  It is located in `Michelson.TypeCheck` and+designed in the following way:+* It takes a core Michelson contract extended with `EXT` instruction+  to support additional instructions described in the+  [`morleyInstructions.md`](language/morleyInstructions.md) document.+* The contract passed to the typechecker uses [untyped+  representation](./michelsonTypes.md).+* During typechecking, we verify that instructions are well-typed and+  provide evidence to the compiler that allows us to convert+  instructions into [typed representation](./michelsonTypes.md). If+  the contract is ill-typed, the typechecking process fails with an+  error.+* The typechecker can check a whole contract or a standalone value+(for example, a lambda).  In the former case it needs to know the+parameter type of the contract (to check `SELF`).  ## CLI  End users can use the `typecheck` command to execute the typechecker.-It parses the contract, performs macro expansion, and passes it to the typechecker which says that the contract is well-typed or produces an error message.+It parses the contract, performs macro expansion, and passes it to the+typechecker which says that the contract is well-typed or produces an+error message. Additionally, one can specify a `--verbose` option to+print stack types between instructions which is useful for debugging. -Example: `morley typecheck --contract auction.tz`.+Example: `morley typecheck --contract auction.tz --verbose`.  ## Internals -An internal structure of the typechecker is pretty well described in Haddock comments.-Two main modules are:-* [`Michelson.TypeCheck.Value`](/code/morley/src/Michelson/TypeCheck/Value.hs) contains logic for checking Michelson values.-* [`Michelson.TypeCheck.Instr`](/code/morley/src/Michelson/TypeCheck/Instr.hs) contains logic for checking Michelson instructions and the whole contract.+An internal structure of the typechecker is pretty well described in+Haddock comments.  Two main modules are:+* [`Michelson.TypeCheck.Value`](/code/morley/src/Michelson/TypeCheck/Value.hs)+  contains logic for checking Michelson values.+* [`Michelson.TypeCheck.Instr`](/code/morley/src/Michelson/TypeCheck/Instr.hs)+  contains logic for checking Michelson instructions and the whole+  contract. -Their functionality is re-exported from the [`Michelson.TypeCheck`](/code/morley/src/Michelson/TypeCheck.hs) module along with some auxiliary types and functions.+Their functionality is re-exported from the+[`Michelson.TypeCheck`](/code/morley/src/Michelson/TypeCheck.hs)+module along with some auxiliary types and functions.
morley.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           morley-version:        1.7.1+version:        1.8.0 synopsis:       Developer tools for the Michelson Language description:    A library to make writing smart contracts in Michelson — the smart contract language of the Tezos blockchain — pleasant and effective. category:       Language@@ -73,6 +73,8 @@       Michelson.TypeCheck.Helpers       Michelson.TypeCheck.Instr       Michelson.TypeCheck.TypeCheck+      Michelson.TypeCheck.TypeCheckedOp+      Michelson.TypeCheck.TypeCheckedSeq       Michelson.TypeCheck.Types       Michelson.TypeCheck.Value       Michelson.Typed@@ -138,9 +140,9 @@       Util.Lens       Util.Markdown       Util.Named+      Util.Num       Util.Peano       Util.Positive-      Util.Test.Arbitrary       Util.Text       Util.TH       Util.Type@@ -157,8 +159,7 @@   default-extensions: AllowAmbiguousTypes ApplicativeDo BangPatterns BlockArguments ConstraintKinds DataKinds DefaultSignatures DeriveAnyClass DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable DerivingStrategies DerivingVia EmptyCase FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses MultiWayIf NamedFieldPuns NegativeLiterals NumDecimals OverloadedLabels OverloadedStrings PatternSynonyms PolyKinds QuasiQuotes RankNTypes RecordWildCards RecursiveDo ScopedTypeVariables StandaloneDeriving StrictData TemplateHaskell TupleSections TypeApplications TypeFamilies TypeOperators UndecidableInstances UndecidableSuperClasses ViewPatterns   ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-implicit-prelude   build-depends:-      QuickCheck-    , aeson+      aeson     , aeson-casing     , aeson-pretty     , base >=4.7 && <5@@ -183,8 +184,6 @@     , named     , optparse-applicative     , parser-combinators >=1.0.0-    , quickcheck-arbitrary-adt-    , quickcheck-instances     , semigroups >=0.19.1     , show-type     , singletons@@ -220,6 +219,7 @@       aeson     , base >=4.7 && <5     , bytestring+    , data-default     , fmt     , haskeline     , megaparsec >=7.0.0
src/Michelson/Doc.hs view
@@ -47,6 +47,7 @@   , DComment (..)   , DAnchor (..)   , DToc (..)+  , DConversionInfo (..)   ) where  import Control.Lens.Cons (_head)@@ -665,3 +666,34 @@   docItemPos = 4   docItemSectionName = Nothing   docItemToMarkdown _ (DAnchor a) = mdAnchor a++data DConversionInfo = DConversionInfo++-- TODO: we should also recommend using morley-client when+-- it'll become good enough+instance DocItem DConversionInfo where+  docItemPos = 15+  docItemSectionName = Just "Haskell ⇄ Michelson conversion"+  docItemToMarkdown _ _ =+    "This smart contract is developed in Haskell using the \+    \[Morley framework](https://gitlab.com/morley-framework/morley). \+    \Documentation mentions Haskell types that can be used for interaction with \+    \this contract from Haskell, but for each Haskell type we also mention its \+    \Michelson representation to make interactions outside of Haskell possible.\n\n\+    \There are multiple ways to interact with this contract:\n\n\+    \* Use this contract in your Haskell application, thus all operation submission\+    \should be handled separately, e.g. via calling `tezos-client`, which will communicate \+    \with the `tezos-node`. In order to be able to call `tezos-client` you'll need to be able \+    \to construct Michelson values from Haskell.\n\n\+    \  The easiest way to do that is to serialize Haskell value using `lPackValue` function \+    \from [`Lorentz.Pack`](https://gitlab.com/morley-framework/morley/-/blob/2441e26bebd22ac4b30948e8facbb698d3b25c6d/code/lorentz/src/Lorentz/Pack.hs) \+    \module, encode resulting bytestring to hexadecimal representation using `encodeHex` function. \+    \Resulting hexadecimal encoded bytes sequence can be decoded back to Michelson value via \+    \`tezos-client unpack michelson data`.\n\n\+    \  Reverse conversion from Michelson value to the \+    \Haskell value can be done by serializing Michelson value using `tezos-client hash data` command, \+    \resulting `Raw packed data` should be decoded from the hexadecimal representation using `decodeHex` \+    \and deserialized to the Haskell value via `lUnpackValue` function from \+    \[`Lorentz.Pack`](https://gitlab.com/morley-framework/morley/-/blob/2441e26bebd22ac4b30948e8facbb698d3b25c6d/code/lorentz/src/Lorentz/Pack.hs).\n\n\+    \* Contruct values for this contract directly on Michelson level using types provided in the \+    \documentation."
src/Michelson/ErrorPos.hs view
@@ -4,6 +4,7 @@  module Michelson.ErrorPos   ( mkPos+  , unsafeMkPos   , Pos (..)   , SrcPos (..)   , srcPos@@ -16,22 +17,33 @@ import Data.Data (Data(..)) import Data.Default (Default(..)) import qualified Data.Text as T-import Fmt (Buildable)+import Fmt (Buildable (..))  import Util.Aeson -newtype Pos = Pos Word+newtype Pos = Pos {unPos :: Word}   deriving stock (Eq, Ord, Show, Generic, Data)  instance NFData Pos -mkPos :: Int -> Pos-mkPos x+unsafeMkPos :: Int -> Pos+unsafeMkPos x   | x < 0     = error $ "negative pos: " <> show x   | otherwise = Pos $ fromIntegral x -data SrcPos = SrcPos Pos Pos-  deriving stock (Eq, Ord, Show, Generic, Data)+mkPos :: Int -> Maybe Pos+mkPos x+  | x < 0     = Nothing+  | otherwise = Just $ Pos $ fromIntegral x++data SrcPos =+  SrcPos+  { srcLine :: Pos+  , srcCol :: Pos+  } deriving stock (Eq, Ord, Show, Generic, Data)++instance Buildable SrcPos where+  build (SrcPos (Pos l) (Pos c)) = build l <> ":" <> build c  instance NFData SrcPos 
src/Michelson/FailPattern.hs view
@@ -2,6 +2,12 @@ -- -- SPDX-License-Identifier: LicenseRef-MIT-TQ +-- NOTE this pragmas.+-- We disable some wargnings for the sake of speed up.+-- Write code with care.+{-# OPTIONS_GHC -Wno-incomplete-patterns #-}+{-# OPTIONS_GHC -Wno-overlapping-patterns #-}+ -- | Typical usages of FAILWITH instruction.  module Michelson.FailPattern@@ -45,25 +51,22 @@ -- passed to other instructions. -- -- The instruction MUST be linearized to the left (see 'linearizeLeft').------ *IMPORTANT* be careful if you want to rewrite this function.--- It took GHC about 30 seconds to compile this function previously.--- The clause @isTypicalPreFailWith (Seq x PAIR) = ..@ is crucial, so please--- don't move these two case branches in this clause outside of it:--- either in different patten matching or in case or \case clause,--- I usually experienced a regression for any of these options. isTypicalFailWith :: Instr inp out -> Maybe TypicalFailWith-isTypicalFailWith (Seq i1 FAILWITH) = isTypicalPreFailWith i1+isTypicalFailWith = \case+  Seq i1 FAILWITH -> isTypicalPreFailWith i1+  _ -> Nothing   where-    isTypicalPreFailWith :: Instr inp (a ': out) -> Maybe TypicalFailWith-    isTypicalPreFailWith (Seq x PAIR) = case x of-      Seq _ (PUSH v) -> FailWithStackValue <$> isStringValue v-      PUSH v         -> FailWithStackValue <$> isStringValue v-      _              -> Nothing-    isTypicalPreFailWith (Seq _ (PUSH v)) = isTypicalErrorConstant v-    isTypicalPreFailWith (PUSH v) = isTypicalErrorConstant v-    isTypicalPreFailWith _ = Nothing-isTypicalFailWith _ = Nothing+    isTypicalPreFailWith ::+      Instr inp (a ': out) -> Maybe TypicalFailWith+    isTypicalPreFailWith =+      \case+        PUSH v -> isTypicalErrorConstant v+        Seq _ (PUSH v) -> isTypicalErrorConstant v++        Seq (PUSH v) PAIR -> FailWithStackValue <$> isStringValue v+        Seq (Seq _ (PUSH v)) PAIR -> FailWithStackValue <$> isStringValue v++        _ -> Nothing  isTypicalErrorConstant ::   forall t. ConstantScope t => Value t -> Maybe TypicalFailWith
src/Michelson/Interpret/Pack.hs view
@@ -34,7 +34,7 @@ import Michelson.Text import Michelson.Typed import Michelson.Untyped.Annotation-  (Annotation(..), FieldAnn, TypeAnn, VarAnn, convAnn, fullAnnSet, isNoAnnSet, noAnn)+  (Annotation(..), FieldAnn, TypeAnn, VarAnn, fullAnnSet, isNoAnnSet, noAnn) import Tezos.Address (Address(..), ContractHash(..)) import Tezos.Core (ChainId(..), Mutez(..), timestampToSeconds) import Tezos.Crypto (KeyHash(..), KeyHashTag(..), PublicKey(..), signatureToBytes)@@ -461,7 +461,7 @@  encodeParamNotes' ::   forall (t :: T). SingI t => ParamNotes t -> LByteString-encodeParamNotes' ParamNotesUnsafe{..} = encodeNotedST (sing @t) (convAnn pnRootAnn) pnNotes+encodeParamNotes' ParamNotesUnsafe{..} = encodeNotedST (sing @t) pnRootAnn pnNotes  -- Note: to encode field annotations we have to accept them as an additional -- parameter because they are stored in the parent's `Notes t`, e.g. see STPair.
src/Michelson/Interpret/Unpack.hs view
@@ -57,6 +57,7 @@ import Tezos.Core import Tezos.Crypto import Util.Binary+import Util.Num  ---------------------------------------------------------------------------- -- Helpers@@ -279,10 +280,9 @@   -- One more reason to go with just 'Int' for now is that we need to be able to   -- deserialize byte arrays, and 'BS.ByteString' keeps length of type 'Int'   -- inside.-  let len' = fromIntegral @_ @Int len-  unless (fromIntegral len' == len && len' >= 0) $-    fail "Length overflow"-  return len'+  fromIntegralChecked len+    & either (fail . toString) pure+    ? "Length"  decodeAsListRaw :: Get a -> Get a decodeAsListRaw getElems = do@@ -375,7 +375,7 @@   => [ExpandedOp]   -> m (RemFail T.Instr '[inp] '[out]) decodeTypeCheckLam uinstr =-  either tcErrToFail pure . evaluatingState tcInitEnv . runExceptT $ do+  either tcErrToFail pure . run $ do     let inp = (starNotes, Dict, noAnn) ::& SNil     _ :/ instr' <- typeCheckList uinstr inp     case instr' of@@ -394,6 +394,7 @@       AnyOutInstr instr ->         return $ RfAlwaysFails instr   where+    run = evaluatingState tcInitEnv . runExceptT . usingReaderT def     tcErrToFail err = fail $ "Type check failed: " +| err |+ ""     tcInitEnv =       TypeCheckEnv@@ -627,7 +628,7 @@       expectTag "Pre contract parameter" 0x05       expectTag "Contract parameter" 0x00       (t, ta, root) <- decodeTWithAnns-      pure $ ParameterType (Type t ta) (convAnn root)+      pure $ ParameterType (Type t ta) root     decodeStorageBlock = CBStorage <$> do       expectTag "Pre contract storage" 0x05       expectTag "Contract storage" 0x01
src/Michelson/OpSize.hs view
@@ -156,7 +156,7 @@  contractOpSize :: Contract -> OpSize contractOpSize (Contract (ParameterType cp rootAnn) st is _) =-  OpSize 16 <> typeOpSize' [convAnn rootAnn] cp <> typeOpSize st <> expandedInstrsOpSize is+  OpSize 16 <> typeOpSize' [rootAnn] cp <> typeOpSize st <> expandedInstrsOpSize is  numOpSize :: Integral i => i -> OpSize numOpSize = OpSize . fromIntegral . length . encodeIntPayload . fromIntegral
src/Michelson/Optimizer.hs view
@@ -2,6 +2,12 @@ -- -- SPDX-License-Identifier: LicenseRef-MIT-TQ +-- NOTE this pragmas.+-- We disable some wargnings for the sake of speed up.+-- Write code with care.+{-# OPTIONS_GHC -Wno-incomplete-patterns #-}+{-# OPTIONS_GHC -Wno-overlapping-patterns #-}+ -- | Optimizer for typed instructions. -- -- It's quite experimental and incomplete.
src/Michelson/Parser.hs view
@@ -35,6 +35,7 @@    -- * Quoters   , utypeQ+  , uparamTypeQ    -- * Re-exports   , errorBundlePretty@@ -42,12 +43,14 @@  import Prelude hiding (try) +import qualified Language.Haskell.TH.Lift as TH import qualified Language.Haskell.TH.Quote as TH-import Text.Megaparsec (Parsec, choice, customFailure, eitherP, eof, errorBundlePretty,-  getSourcePos, lookAhead, parse, try)+import Text.Megaparsec+  (Parsec, choice, customFailure, eitherP, eof, errorBundlePretty, getSourcePos, lookAhead, parse,+  try) import Text.Megaparsec.Pos (SourcePos(..), unPos) -import Michelson.ErrorPos (SrcPos(..), mkPos)+import Michelson.ErrorPos (SrcPos(..), unsafeMkPos) import Michelson.Macro (LetMacro, Macro(..), ParsedInstr, ParsedOp(..), ParsedValue, expandValue) import Michelson.Parser.Annotations (noteF) import Michelson.Parser.Error@@ -92,8 +95,10 @@       local (const env) contract  cbParameter :: Parser ParameterType-cbParameter = do-  symbol "parameter"+cbParameter = symbol "parameter" *> cbParameterBare++cbParameterBare :: Parser ParameterType+cbParameterBare = do   prefixRootAnn <- optional noteF   (inTypeRootAnn, t) <- field   rootAnn <- case (prefixRootAnn, inTypeRootAnn) of@@ -103,7 +108,7 @@     (Just a, "") -> pure a     (Nothing, b) -> pure b     (Just _, _) -> customFailure MultiRootAnnotationException-  pure $ ParameterType t (convAnn rootAnn)+  pure $ ParameterType t rootAnn  cbStorage :: Parser Type cbStorage = symbol "storage" *> type_@@ -219,7 +224,7 @@   let l = unPos $ sourceLine sp   let c = unPos $ sourceColumn sp   -- reindexing starting from 0-  pure $ SrcPos (mkPos $ l - 1) (mkPos $ c - 1)+  pure $ SrcPos (unsafeMkPos $ l - 1) (unsafeMkPos $ c - 1)  primWithPos :: Parser ParsedInstr -> Parser ParsedOp primWithPos act = do@@ -260,17 +265,25 @@ -- Safe construction of Haskell values ------------------------------------------------------------------------------- --- | Creates 'U.Type' by its Morley representation.------ >>> [utypeQ| (int :a | nat :b) |]--- Type (TOr % % (Type (Tc CInt) :a) (Type (Tc CNat) :b)) :-utypeQ :: TH.QuasiQuoter-utypeQ = TH.QuasiQuoter+parserToQuasiQuoter :: TH.Lift a => Parser a -> TH.QuasiQuoter+parserToQuasiQuoter parser = TH.QuasiQuoter   { TH.quoteExp = \s ->-      case parseNoEnv (mSpace *> type_) "QuasiQuoter" (toText s) of+      case parseNoEnv (mSpace *> parser) "QuasiQuoter" (toText s) of         Left err -> fail $ errorBundlePretty err         Right res -> [e| res |]   , TH.quotePat = \_ -> fail "Cannot be used as pattern"   , TH.quoteType = \_ -> fail "Cannot be used as type"   , TH.quoteDec = \_ -> fail "Cannot be used as declaration"   }+++-- | Creates 'U.Type' by its Morley representation.+--+-- >>> [utypeQ| (int :a | nat :b) |]+-- Type (TOr % % (Type (Tc CInt) :a) (Type (Tc CNat) :b)) :+utypeQ :: TH.QuasiQuoter+utypeQ = parserToQuasiQuoter type_++-- | Creates 'U.ParameterType' by its Morley representation.+uparamTypeQ :: TH.QuasiQuoter+uparamTypeQ = parserToQuasiQuoter cbParameterBare
src/Michelson/Printer/Util.hs view
@@ -10,6 +10,7 @@   , printDocS   , renderOps   , renderOpsList+  , renderOpsListNoBraces   , spaces   , wrapInParens   , buildRenderDoc@@ -81,10 +82,12 @@  renderOpsList :: (RenderDoc op) => Bool -> [op] -> Doc renderOpsList oneLine ops =-  braces $-    enclose space space $-      cat' $ punctuate semi $-        renderDoc doesntNeedParens <$> filter isRenderable ops+  braces $ enclose space space $ renderOpsListNoBraces oneLine ops++renderOpsListNoBraces :: RenderDoc op => Bool -> [op] -> Doc+renderOpsListNoBraces oneLine ops =+  cat' $ punctuate semi $+    renderDoc doesntNeedParens <$> filter isRenderable ops   where     cat' = if oneLine then maybe "" spacecat . nonEmpty else align . vcat 
src/Michelson/Text.hs view
@@ -44,7 +44,6 @@ import Fmt (Buildable) import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH.Quote as TH-import Test.QuickCheck (Arbitrary(..), choose, listOf)  import Util.CLI import Util.Label (Label(..), labelToText)@@ -129,11 +128,6 @@  instance ToText MText where   toText = unMText--instance Arbitrary MText where-  arbitrary =-    mkMTextUnsafe . toText <$>-    listOf (choose @Char (toEnum minBoundMChar, toEnum maxBoundMChar))  instance ToJSON MText where   toJSON = toJSON . unMText
src/Michelson/TypeCheck.hs view
@@ -5,13 +5,15 @@ module Michelson.TypeCheck   ( typeCheckContract   , typeCheckContractAndStorage-  , typeCheckStorage+  , typeCheckExt+  , typeCheckInstr+  , typeCheckList+  , typeCheckListNoExcept   , typeCheckParameter-  , typeVerifyStorage-  , typeVerifyParameter+  , typeCheckStorage   , typeCheckValue-  , typeCheckList-  , typeCheckExt+  , typeVerifyParameter+  , typeVerifyStorage   , module E   , module M   , module T
src/Michelson/TypeCheck/Error.hs view
@@ -17,6 +17,8 @@ import qualified Text.Show (show)  import Michelson.ErrorPos (InstrCallStack(..), Pos(..), SrcPos(..))+import Michelson.Printer.Util (doesntNeedParens, printDocB, renderDoc)+import Michelson.TypeCheck.TypeCheckedOp (TypeCheckedOp) import Michelson.TypeCheck.Types (SomeHST(..)) import qualified Michelson.Typed as T import Michelson.Typed.Annotation (AnnConvergeError(..))@@ -242,6 +244,7 @@   | TCContractError Text (Maybe TCTypeError)   | TCUnreachableCode InstrCallStack (NonEmpty U.ExpandedOp)   | TCExtError SomeHST InstrCallStack ExtError+  | TCIncompletelyTyped TCError (U.Contract' TypeCheckedOp)   deriving stock (Eq, Generic)  instance NFData TCError@@ -270,6 +273,10 @@       "Error occurred during Morley extension typecheck: "       +| e |+ " on stack " +| t |+ ". "       +| buildCallStack ics+    TCIncompletelyTyped err contract ->+      "\n"+      +| printDocB False (renderDoc doesntNeedParens contract) |+ "\n"+      +| build err     where     buildTruncated k l       | null (drop k l) = build l@@ -280,10 +287,10 @@            [] -> "."            _ -> " inside these let defenitions: " +| listF icsCallStack |+ "." -instance Buildable U.ExpandedInstr => Show TCError where+instance Show TCError where   show = pretty -instance Buildable U.ExpandedInstr => Exception TCError+instance Exception TCError  newtype StackSize = StackSize Natural   deriving stock (Show, Eq, Generic)
src/Michelson/TypeCheck/Ext.hs view
@@ -8,8 +8,8 @@   ) where  import Control.Lens ((%=))-import Data.Constraint (Dict(..)) import Control.Monad.Except (MonadError, liftEither, throwError)+import Data.Constraint (Dict(..)) import Data.Map.Lazy (insert, lookup) import Data.Typeable ((:~:)(..)) @@ -17,6 +17,7 @@ import Michelson.TypeCheck.Error import Michelson.TypeCheck.Helpers import Michelson.TypeCheck.TypeCheck+import Michelson.TypeCheck.TypeCheckedSeq (IllTypedInstr(..), TypeCheckedSeq(..)) import Michelson.TypeCheck.Types import Michelson.Typed (Notes(..), converge, mkUType, notesT, withUType) import qualified Michelson.Typed as T@@ -26,44 +27,52 @@ import qualified Michelson.Untyped as U import Util.Peano (SingNat(SS, SZ)) -type TypeCheckListHandler inp =-     [U.ExpandedOp]-  -> HST inp-  -> TypeCheck (SomeInstr inp)+-- | Perform some, possibly throwing, action presumably making use of a supplied+-- external instruction. In case of an error, return @IllTypedSeq@ wrapping the+-- thrown error and the instruction. If the action successfully returns+-- @SomeInstr@, wrap it in a @WellTypedSeq@.+workOnInstr+  :: U.ExpandedExtInstr+  -> TypeCheckInstr (SomeInstr s)+  -> TypeCheckInstrNoExcept (TypeCheckedSeq s)+workOnInstr ext = tcEither+  (\err -> pure $ IllTypedSeq err [NonTypedInstr $ U.PrimEx $ U.EXT ext])+  (pure . WellTypedSeq)  typeCheckExt-  :: forall s.-     (Typeable s)-  => TypeCheckListHandler s+  :: forall s. Typeable s+  => TcInstrHandler   -> U.ExpandedExtInstr   -> HST s-  -> TypeCheckInstr (SomeInstr s)-typeCheckExt typeCheckListH ext hst = do+  -> TypeCheckInstrNoExcept (TypeCheckedSeq s)+typeCheckExt tcInstr ext hst = do   instrPos <- ask   case ext of-    U.STACKTYPE s -> liftExtError hst $ nopSomeInstr <$ checkStackType noBoundVars s hst-    U.FN t sf op  -> checkFn typeCheckListH t sf op hst-    U.UPRINT pc   -> verifyPrint pc <&> \tpc -> toSomeInstr (T.PRINT tpc)+    U.STACKTYPE s -> workOnInstr ext $+      liftExtError hst $ nopSomeInstr <$ checkStackType noBoundVars s hst+    U.FN t sf op  -> checkFn tcInstr t sf op hst+    U.UPRINT pc   -> workOnInstr ext $+      verifyPrint pc <&> \tpc -> toSomeInstr (T.PRINT tpc)     U.UTEST_ASSERT U.TestAssert{..} -> do-      verifyPrint tassComment-      _ :/ si <- lift $ typeCheckListH tassInstrs hst-      case si of+      let cons = U.EXT . U.UTEST_ASSERT . U.TestAssert tassName tassComment+      preserving (typeCheckImpl tcInstr tassInstrs hst) cons $ \(_ :/ si) -> case si of         AnyOutInstr _ -> throwError $ TCExtError (SomeHST hst) instrPos $ TestAssertError                          "TEST_ASSERT has to return Bool, but it always fails"-        instr ::: (((_ :: (T.Notes b, Dict (T.WellTyped b), VarAnn)) ::& (_ :: HST out1))) -> do-          Refl <- liftEither $-                    first (const $ TCExtError (SomeHST hst) instrPos $-                           TestAssertError "TEST_ASSERT has to return Bool, but returned something else") $-                      eqType @b @'T.TBool+        instr ::: (((_ :: (T.Notes b, Dict (T.WellTyped b), VarAnn)) ::& _)) -> do+          Refl <- liftEither $ first+            (const $ TCExtError (SomeHST hst) instrPos $+              TestAssertError "TEST_ASSERT has to return Bool, but returned something else")+            (eqType @b @'T.TBool)           tcom <- verifyPrint tassComment           pure . toSomeInstr $ T.TEST_ASSERT $ T.TestAssert tassName tcom instr         _ ->           throwError $ TCExtError (SomeHST hst) instrPos $             TestAssertError "TEST_ASSERT has to return Bool, but the stack is empty"+     U.UCOMMENT t ->       -- TODO if we are going to analyze/parse programs from files,       -- there should be parsing of string and creation of FunctionStarted/FunctionFinished/etc-      pure $ toSomeInstr $ T.COMMENT_ITEM $ T.JustComment t+      pure $ WellTypedSeq $ toSomeInstr $ T.COMMENT_ITEM $ T.JustComment t   where     verifyPrint :: U.PrintComment -> TypeCheckInstr (T.PrintComment s)     verifyPrint (U.PrintComment pc) = do@@ -90,19 +99,18 @@ -- the pattern in @FN@. checkFn   :: Typeable inp-  => TypeCheckListHandler inp+  => TcInstrHandler   -> Text   -> StackFn   -> [ExpandedOp]   -> HST inp-  -> TypeCheckInstr (SomeInstr inp)-checkFn typeCheckListH t sf body inp = do-  vars <- checkStart inp-  res@(_ :/ instr) <- lift $ typeCheckListH body inp-  case instr of-    _ ::: out -> checkEnd vars out-    AnyOutInstr _ -> pass-  return res+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+checkFn tcInstr t sf body inp = do+  guarding (con body) (checkStart inp) $ \vars ->+    preserving (typeCheckImplStripped tcInstr body inp) con $ \someI@(_ :/ instrAndOut) ->+      case instrAndOut of+        _ ::: out -> checkEnd vars out $> someI+        AnyOutInstr{} -> pure someI   where     checkStart hst = do       liftExtError hst $ checkVars t sf@@ -113,6 +121,9 @@     checkEnd :: Typeable out => BoundVars -> HST out -> TypeCheckInstr ()     checkEnd vars out = liftExtError out $       void $ checkStackType vars (sfnOutPattern sf) out++    con :: [op] -> U.InstrAbstract op+    con = U.EXT . U.FN t sf  -- | Check that a @StackTypePattern@ matches the type of the current stack checkStackType
src/Michelson/TypeCheck/Helpers.hs view
@@ -24,6 +24,7 @@     , typeCheckInstrErr     , typeCheckInstrErr'     , typeCheckImpl+    , typeCheckImplStripped     , matchTypes      , memImpl@@ -56,9 +57,11 @@ import Michelson.TypeCheck.Error (TCError(..), TCTypeError(..), TypeContext(..)) import Michelson.TypeCheck.TypeCheck import Michelson.TypeCheck.Types+import Michelson.TypeCheck.TypeCheckedSeq (IllTypedInstr(..), TypeCheckedSeq(..)) import Michelson.Typed-  (BadTypeForScope(..), Comparable, Instr(..), KnownT, Notes(..), PackedNotes(..), SingT(..),-  T(..), WellTyped, converge, getComparableProofS, notesT, orAnn, starNotes)+  (BadTypeForScope(..), CommentType(StackTypeComment), Comparable, ExtInstr(COMMENT_ITEM),+  Instr(..), KnownT, Notes(..), PackedNotes(..), SingT(..), T(..), WellTyped, converge,+  getComparableProofS, notesT, orAnn, starNotes) import Michelson.Typed.Annotation (AnnConvergeError, isStar) import Michelson.Typed.Arith (Add, ArithOp(..), Mul, Sub, UnaryArithOp(..)) import Michelson.Typed.Polymorphic@@ -254,73 +257,171 @@   Just d@Dict -> pure $ withDict d act   Nothing -> typeCheckInstrErr instr (SomeHST i) $ Just ComparisonArguments -typeCheckImpl-  :: forall inp . Typeable inp+typeCheckOpImpl+  :: forall inp. Typeable inp   => TcInstrHandler-  -> [Un.ExpandedOp]+  -> Un.ExpandedOp   -> HST inp-  -> TypeCheckInstr (SomeInstr inp)-typeCheckImpl tcInstr instrs t@(a :: HST a) =-  case instrs of-    Un.WithSrcEx _ (i@(Un.WithSrcEx _ _)) : rs -> typeCheckImpl tcInstr (i : rs) t-    Un.WithSrcEx cs (Un.PrimEx i) : rs -> typeCheckPrim (Just cs) i rs-    Un.WithSrcEx cs (Un.SeqEx sq) : rs -> typeCheckSeq (Just cs) sq rs-    Un.PrimEx i : rs                 -> typeCheckPrim Nothing i rs-    Un.SeqEx sq : rs                 -> typeCheckSeq Nothing sq rs-    []                               -> pure $ a :/ Nop ::: a+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+typeCheckOpImpl tcInstr op' inputStack = case op' of+  Un.WithSrcEx _ op@Un.WithSrcEx{} -> typeCheckOpImpl tcInstr op inputStack+  Un.WithSrcEx loc (Un.PrimEx op)  -> typeCheckPrimWithLoc loc op+  Un.WithSrcEx loc (Un.SeqEx sq)   -> typeCheckSeqWithLoc loc sq+  Un.PrimEx op                     -> typeCheckPrim op+  Un.SeqEx sq                      -> typeCheckSeq sq   where     -- If we know source location from the untyped instruction, keep it in the typed one.-    typeCheckPrim (Just cs) i [] = local (const cs) $ (tcInstr i t <&> wrapWithLoc cs)-    typeCheckPrim (Just cs) i rs = local (const cs) $ typeCheckImplDo (tcInstr i t <&> wrapWithLoc cs) id rs-    typeCheckPrim Nothing i [] = tcInstr i t-    typeCheckPrim Nothing i rs = typeCheckImplDo (tcInstr i t) id rs+    typeCheckPrimWithLoc loc op = local (const loc)+      (wrapWithLoc loc <$> typeCheckPrim op) -    typeCheckSeq (Just cs) sq = local (const cs) . typeCheckImplDo (typeCheckImpl tcInstr sq t) Nested-    typeCheckSeq Nothing sq = typeCheckImplDo (typeCheckImpl tcInstr sq t) Nested+    typeCheckPrim op = tcInstr op inputStack <&> mapSeq addNotes -    wrapWithLoc :: InstrCallStack -> SomeInstr inp -> SomeInstr inp-    wrapWithLoc _ si@(_ :/ (WithLoc _ _) ::: _) = si-    wrapWithLoc cs (inp :/ instr ::: out) = inp :/ WithLoc cs instr ::: out-    wrapWithLoc _ si = si+    typeCheckSeqWithLoc loc = local (const loc) . typeCheckSeq -    typeCheckImplDo-      :: TypeCheckInstr (SomeInstr inp)-      -> (forall inp' out . Instr inp' out -> Instr inp' out)-      -> [Un.ExpandedOp]-      -> TypeCheckInstr (SomeInstr inp)-    typeCheckImplDo f wrap rs = do-      _ :/ pi' <- f-      case pi' of-        p ::: b -> do-          _ :/ qi <- typeCheckImpl tcInstr rs b-          case qi of-            q ::: c -> case q of-              Seq _ _ ->-                pure $ a :/ Seq (wrapWithNotes b (wrap p)) q ::: c-              -- Wrap the RHS if it is a single instruction and not a-              -- sequence-              _ ->-                pure $ a :/ Seq (wrapWithNotes b (wrap p)) (wrapWithNotes c q) ::: c-            AnyOutInstr q ->-              pure $ a :/ AnyOutInstr (Seq (wrapWithNotes b (wrap p)) q)+    typeCheckSeq sq = typeCheckImpl tcInstr sq inputStack+                  <&> mapSeq (addNotes . mapSomeInstr Nested) -        AnyOutInstr instr ->-          case rs of-            [] ->-              pure $ a :/ AnyOutInstr instr-            r : rr ->-              throwError $ TCUnreachableCode (extractInstrPos r) (r :| rr)+    addNotes (inp :/ i ::: out) = inp :/ wrapWithNotes out i ::: out+    addNotes i = i      wrapWithNotes :: HST d -> Instr c d -> Instr c d-    wrapWithNotes h ins = case h of+    wrapWithNotes outputStack instr = case outputStack of       -- do not wrap in notes if the notes are "star"-      ((n, _, _) ::& _) | isStar n -> ins-      ((n, _, _) ::& _) -> InstrWithNotes (PackedNotes n) ins-      SNil -> ins+      ((n, _, _) ::& _) | isStar n -> instr+      ((n, _, _) ::& _) -> InstrWithNotes (PackedNotes n) instr+      SNil -> instr -    extractInstrPos :: Un.ExpandedOp -> InstrCallStack-    extractInstrPos (Un.WithSrcEx cs _) = cs-    extractInstrPos _ = def+-- | Like 'typeCheckImpl' but doesn't add a stack type comment after the+-- sequence.+typeCheckImplNoLastTypeComment+  :: forall inp . Typeable inp+  => TcInstrHandler+  -> [Un.ExpandedOp]+  -> HST inp+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+typeCheckImplNoLastTypeComment _ [] inputStack+  = pure (WellTypedSeq (inputStack :/ Nop ::: inputStack))+typeCheckImplNoLastTypeComment tcInstr (op : ops) inputStack = do+  done <- typeCheckOpImpl tcInstr op inputStack+      >>= mapMSeq prependStackTypeComment+  continueTypeChecking tcInstr done ops++continueTypeChecking+  :: forall inp. ()+  => TcInstrHandler+  -> TypeCheckedSeq inp+  -> [Un.ExpandedOp]+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+continueTypeChecking tcInstr done rest = case done of+  WellTypedSeq instr -> handleFirst instr+  MixedSeq i e left -> pure (MixedSeq i e (left <> map NonTypedInstr rest))+  IllTypedSeq e left -> pure (IllTypedSeq e (left <> map NonTypedInstr rest))+  where+    handleFirst :: SomeInstr inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+    handleFirst packedInstr@(inputStack :/ instrAndOutputStack) = do+      case instrAndOutputStack of+        instr ::: outputStack -> do+          nextPiece <- typeCheckImplNoLastTypeComment tcInstr rest outputStack+          let combiner = combine inputStack instr+          pure case nextPiece of+            WellTypedSeq nextInstr -> WellTypedSeq (combiner nextInstr)+            MixedSeq nextInstr err left -> MixedSeq (combiner nextInstr) err left+            IllTypedSeq err left -> MixedSeq packedInstr err left+        AnyOutInstr{} -> pure case rest of+          [] -> WellTypedSeq packedInstr+          op : ops -> (MixedSeq+                        packedInstr+                        (TCUnreachableCode (extractOpPos op) (op :| ops))+                        (map NonTypedInstr ops))++    combine inp i1 (_ :/ nextPart) = inp :/ mapSomeInstrOut (Seq i1) nextPart++    extractOpPos :: Un.ExpandedOp -> InstrCallStack+    extractOpPos (Un.WithSrcEx loc _) = loc+    extractOpPos _ = def++-- | Like 'typeCheckImpl' but without the first and the last stack type+-- comments. Useful to reduce duplication of stack type comments.+typeCheckImplStripped+  :: forall inp . Typeable inp+  => TcInstrHandler+  -> [Un.ExpandedOp]+  -> HST inp+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+typeCheckImplStripped tcInstr [] inp+  = typeCheckImplNoLastTypeComment tcInstr [] inp+typeCheckImplStripped tcInstr (op : ops) inp = do+  done <- typeCheckOpImpl tcInstr op inp+  continueTypeChecking tcInstr done ops++typeCheckImpl+  :: forall inp . Typeable inp+  => TcInstrHandler+  -> [Un.ExpandedOp]+  -> HST inp+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+typeCheckImpl tcInstr ops inputStack = do+  tcSeq <- typeCheckImplNoLastTypeComment tcInstr ops inputStack+  mapMSeq appendTypeComment tcSeq+  where+    appendTypeComment packedI@(inp :/ iAndOut) = do+      verbose <- lift (asks tcVerbose)+      pure case (verbose, iAndOut) of+        (True, i ::: out) -> inp :/ Seq i (stackTypeComment out) ::: out+        (True, AnyOutInstr i) -> inp :/ AnyOutInstr (Seq i noStackTypeComment)+        _ -> packedI+++prependStackTypeComment+  :: SomeInstr inp -> TypeCheckInstrNoExcept (SomeInstr inp)+prependStackTypeComment packedInstr@(inp :/ _) = do+  verbose <- lift (asks tcVerbose)+  pure if verbose && (not (isNop' packedInstr))+    then mapSomeInstr (Seq (stackTypeComment inp)) packedInstr+    else packedInstr++isNop' :: SomeInstr inp -> Bool+isNop' (_ :/ i ::: _) = isNop i+isNop' (_ :/ AnyOutInstr i) = isNop i++isNop :: Instr inp out -> Bool+isNop (WithLoc _ i) = isNop i+isNop (InstrWithNotes _ i) = isNop i+isNop (InstrWithVarNotes _ i) = isNop i+isNop (FrameInstr _ i) = isNop i+isNop (Seq i1 i2) = isNop i1 && isNop i2+isNop (Nested i) = isNop i+isNop Nop = True+isNop (Ext _) = True+isNop _ = False++mapMSeq+  :: Applicative f+  => (SomeInstr inp -> f (SomeInstr inp'))+  -> TypeCheckedSeq inp+  -> f (TypeCheckedSeq inp')+mapMSeq f v = case v of+  WellTypedSeq instr -> f instr <&> WellTypedSeq+  MixedSeq instr err tail' -> f instr <&> \instr' -> MixedSeq instr' err tail'+  IllTypedSeq err tail' -> pure $ IllTypedSeq err tail'++mapSeq+  :: (SomeInstr inp -> SomeInstr inp')+  -> TypeCheckedSeq inp+  -> TypeCheckedSeq inp'+mapSeq f = runIdentity . mapMSeq (Identity . f)++stackTypeComment :: HST st -> Instr st st+stackTypeComment = Ext . COMMENT_ITEM . StackTypeComment . Just . hstToTs++noStackTypeComment :: Instr st st+noStackTypeComment = Ext (COMMENT_ITEM (StackTypeComment Nothing))++wrapWithLoc :: InstrCallStack -> TypeCheckedSeq inp -> TypeCheckedSeq inp+wrapWithLoc loc = mapSeq $ \someInstr -> case someInstr of+  (_ :/ WithLoc{} ::: _) -> someInstr+  (inp :/ instr ::: out) -> inp :/ WithLoc loc instr ::: out+  _ -> someInstr  -- | Check whether given types are structurally equal and annotations converge. matchTypes
src/Michelson/TypeCheck/Instr.hs view
@@ -31,17 +31,19 @@ module Michelson.TypeCheck.Instr     ( typeCheckContract     , typeCheckContractAndStorage-    , typeCheckValue+    , typeCheckInstr     , typeCheckList-    , typeVerifyStorage-    , typeVerifyParameter-    , typeCheckStorage+    , typeCheckListNoExcept     , typeCheckParameter+    , typeCheckStorage+    , typeCheckValue+    , typeVerifyParameter+    , typeVerifyStorage     ) where  import Prelude hiding (EQ, GT, LT) -import Control.Monad.Except (MonadError, liftEither, throwError)+import Control.Monad.Except (MonadError, liftEither, throwError, catchError) import Data.Default (def) import Data.Generics (everything, mkQ) import Data.Singletons (Sing, demote)@@ -52,6 +54,8 @@ import Michelson.TypeCheck.Ext import Michelson.TypeCheck.Helpers import Michelson.TypeCheck.TypeCheck+import Michelson.TypeCheck.TypeCheckedSeq+  (IllTypedInstr(..), TypeCheckedInstr, TypeCheckedOp(..), TypeCheckedSeq(..), tcsEither, someInstrToOp) import Michelson.TypeCheck.Types import Michelson.TypeCheck.Value import Michelson.Typed.Value@@ -66,16 +70,17 @@ -- is of the type expected by the contract. typeCheckContractAndStorage :: U.Contract -> U.Value -> Either TCError SomeContractAndStorage typeCheckContractAndStorage uContract uStorage = do-  SomeContract (contract@Contract{} :: Contract cp st) <- typeCheckContract uContract+  SomeContract (contract@Contract{} :: Contract cp st) <- typeCheckContract uContract def   storage <- typeVerifyStorage @st uStorage   Right $ SomeContractAndStorage contract storage  typeCheckContract   :: U.Contract+  -> TypeCheckOptions   -> Either TCError SomeContract-typeCheckContract c = do+typeCheckContract c options = do   paramType <- mkSomeParamType (U.contractParameter c)-  runTypeCheck (TypeCheckContract paramType) $ typeCheckContractImpl c+  runTypeCheck (TypeCheckContract paramType) options $ typeCheckContractImpl c  withWTP :: forall t a. SingI t => (WellTyped t => TypeCheck a) -> TypeCheck a withWTP fn = case getWTP @t of@@ -89,10 +94,24 @@     loc <- ask     throwError $ TCFailedOnInstr v t loc Nothing (Just $ UnsupportedTypeForScope badType BtNotComparable) +withWTPInstr'_+  :: forall t inp. SingI t+  => U.ExpandedInstr+  -> SomeHST+  -> (WellTyped t => TypeCheckInstrNoExcept (TypeCheckedSeq inp))+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+withWTPInstr'_ v t fn = case getWTP @t of+  Right Dict -> fn+  Left (NotWellTyped badType) -> do+    loc <- ask+    let err = TCFailedOnInstr v t loc Nothing+              (Just $ UnsupportedTypeForScope badType BtNotComparable)+    pure $ IllTypedSeq err [NonTypedInstr $ U.PrimEx v]+ typeCheckContractImpl   :: U.Contract   -> TypeCheck SomeContract-typeCheckContractImpl (U.Contract (U.ParameterType mParam rootAnn) mStorage pCode entriesOrder) = do+typeCheckContractImpl (U.Contract wholeParam@(U.ParameterType mParam rootAnn) mStorage pCode entriesOrder) = do   _ <- maybe (throwError $ TCContractError "no instructions in contract code" $ Just EmptyCode)                 pure (nonEmpty pCode)   withUType mParam $ \(paramNote :: Notes param) ->@@ -105,41 +124,71 @@             $ checkScope @(StorageScope st)           let inpNote = NTPair def def def paramNote storageNote           let inp = (inpNote, Dict, def) ::& SNil-          inp' :/ instrOut <- usingReaderT def $ typeCheckImpl typeCheckInstr pCode inp-          let (paramNotesRaw, cStoreNotes) = case inp' of-                (NTPair _ _ _ cpNotes stNotes, _, _) ::& SNil -> (cpNotes, stNotes)-          cParamNotes <--            liftEither $-            mkParamNotes paramNotesRaw rootAnn `onLeft`-                (TCContractError "invalid parameter declaration: " . Just . IllegalParamDecl)-          case instrOut of-            instr ::: out -> liftEither $ do-              case eqHST1 @(ContractOut1 st) out of-                Right Refl -> do-                  let (outN, _, _) ::& SNil = out-                  _ <- converge outN (NTPair def def def starNotes storageNote)-                          `onLeft`-                      ((TCContractError "contract output type violates convention:") . Just . AnnError)-                  pure $ SomeContract Contract-                    { cCode = instr-                    , cParamNotes-                    , cStoreNotes-                    , cEntriesOrder = entriesOrder-                    }-                Left err -> Left $ TCContractError "contract output type violates convention:" $ Just err-            AnyOutInstr instr ->++          codeRes <- usingReaderT def $+                     liftNoExcept $+                     typeCheckImpl typeCheckInstr pCode inp+          codeRes & tcsEither+            (onFailedTypeCheck)+            (onSuccessfulTypeCheck (NTPair def def def starNotes storageNote))+  where+    hasTypeError :: forall (t :: T) a. SingI t => Text -> BadTypeForScope -> TypeCheck a+    hasTypeError name reason = throwError $+      TCContractError ("contract " <> name <> " type error") $+      Just $ UnsupportedTypeForScope (demote @t) reason++    onFailedTypeCheck :: [TypeCheckedOp] -> TCError -> TypeCheck SomeContract+    onFailedTypeCheck ops err = do+      verbose <- asks tcVerbose+      throwError if verbose+        then TCIncompletelyTyped err U.Contract+             { contractParameter = wholeParam+             , contractStorage = mStorage+             , contractCode = ops+             , entriesOrder = entriesOrder+             }+        else err++    onSuccessfulTypeCheck+      :: forall st param+      . (ParameterScope param, StorageScope st, WellTyped st)+      => Notes (ContractOut1 st)+      -> SomeInstr (ContractInp param st)+      -> TypeCheck SomeContract+    onSuccessfulTypeCheck outNote i@(inp' :/ instrOut) = wrapErrorsIfVerbose i $ do+      let (paramNotesRaw, cStoreNotes) = case inp' of+            (NTPair _ _ _ cpNotes stNotes, _, _) ::& SNil -> (cpNotes, stNotes)+      cParamNotes <-+        liftEither $+        mkParamNotes paramNotesRaw rootAnn `onLeft`+            (TCContractError "invalid parameter declaration: " . Just . IllegalParamDecl)+      case instrOut of+        instr ::: out -> liftEither $ do+          case eqHST1 @(ContractOut1 st) out of+            Right Refl -> do+              let (outN, _, _) ::& SNil = out+              _ <- converge outN outNote+                      `onLeft`+                  ((TCContractError "contract output type violates convention:") . Just . AnnError)               pure $ SomeContract Contract                 { cCode = instr                 , cParamNotes                 , cStoreNotes                 , cEntriesOrder = entriesOrder                 }-  where-    hasTypeError :: forall (t :: T) a. SingI t => Text -> BadTypeForScope -> TypeCheck a-    hasTypeError name reason = throwError $-      TCContractError ("contract " <> name <> " type error") $-      Just $ UnsupportedTypeForScope (demote @t) reason+            Left err -> Left $ TCContractError "contract output type violates convention:" $ Just err+        AnyOutInstr instr ->+          pure $ SomeContract Contract+            { cCode = instr+            , cParamNotes+            , cStoreNotes+            , cEntriesOrder = entriesOrder+            } +    wrapErrorsIfVerbose :: SomeInstr inp -> TypeCheck SomeContract -> TypeCheck SomeContract+    wrapErrorsIfVerbose instr action =+      action `catchError` (onFailedTypeCheck [someInstrToOp instr])+ -- | Function @typeCheckList@ converts list of Michelson instructions -- given in representation from @Michelson.Type@ module to representation -- in strictly typed GADT.@@ -153,8 +202,19 @@   => [U.ExpandedOp]   -> HST inp   -> TypeCheck (SomeInstr inp)-typeCheckList = usingReaderT def ... typeCheckImpl typeCheckInstr+typeCheckList = throwingTCError' ... typeCheckListNoExcept +-- | Function @typeCheckListNoExcept@ converts list of Michelson instructions+-- given in representation from @Michelson.Type@ module to representation in a+-- partially typed tree. See @TypeCheckedSeq@ and @TypeCheckedOp@.+--+-- Types are checked along the way. It is necessary to embed well typed node as+-- well as type checking errors into the tree.+typeCheckListNoExcept+  :: (Typeable inp)+  => [U.ExpandedOp] -> HST inp -> TypeCheckNoExcept (TypeCheckedSeq inp)+typeCheckListNoExcept = usingReaderT def ... typeCheckImpl typeCheckInstr+ -- | Function @typeCheckValue@ converts a single Michelson value -- given in representation from @Michelson.Untyped@ module hierarchy to -- representation in strictly typed GADT.@@ -187,7 +247,7 @@   :: forall t. SingI t   => Maybe TcOriginatedContracts -> U.Value -> Either TCError (Value t) typeVerifyTopLevelType mOriginatedContracts valueU =-  runTypeCheck (TypeCheckValue (valueU, demote @t)) $ usingReaderT (def :: InstrCallStack) $+  runTypeCheck (TypeCheckValue (valueU, demote @t)) def $ usingReaderT def $     typeCheckValImpl mOriginatedContracts typeCheckInstr valueU  -- | Like 'typeCheckValue', but for values to be used as parameter.@@ -230,6 +290,22 @@     (Typeable out, ConstraintDUG n inp out a) =>     Sing n -> HST out -> TCDugHelper inp +-- Helper function to convert a simple throwing typechecking action into a+-- non-throwing one, embedding possible errors into the type checking tree.+workOnInstr+  :: U.ExpandedInstr+  -> TypeCheckInstr (SomeInstr s)+  -> TypeCheckInstrNoExcept (TypeCheckedSeq s)+workOnInstr instr = tcEither+  (\err -> pure $ IllTypedSeq err [NonTypedInstr $ U.PrimEx instr])+  (pure . WellTypedSeq)++-- Less verbose version of `lift ... typeCheckListNoExcept`.+tcList+  :: (Typeable inp)+  => [U.ExpandedOp] -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+tcList ops stack = lift $ typeCheckListNoExcept ops stack+ -- | Function @typeCheckInstr@ converts a single Michelson instruction -- given in representation from @Michelson.Type@ module to representation -- in strictly typed GADT.@@ -246,13 +322,13 @@ typeCheckInstr :: TcInstrHandler typeCheckInstr uInstr inp = case (uInstr, inp) of   (U.EXT ext, si) ->-    typeCheckExt typeCheckList ext si+    typeCheckExt typeCheckInstr ext si -  (U.DROP, _ ::& rs) -> pure (inp :/ DROP ::: rs)+  (U.DROP, _ ::& rs) -> workOnInstr uInstr $ pure $ inp :/ DROP ::: rs    (U.DROP, SNil) -> notEnoughItemsOnStack -  (U.DROPN nTotal, inputHST) ->+  (U.DROPN nTotal, inputHST) -> workOnInstr uInstr $     go nTotal inputHST <&> \case       TCDropHelper s out -> inputHST :/ DROPN s ::: out     where@@ -263,22 +339,22 @@       go n i = case (n, i) of         (0, _) -> pure (TCDropHelper SZ i) -        (_, SNil) -> notEnoughItemsOnStack+        (_, SNil) -> notEnoughItemsOnStack'          (_, (_ ::& iTail)) -> do           go (n - 1) iTail <&> \case TCDropHelper s out -> TCDropHelper (SS s) out -  (U.DUP _vn, a ::& rs) ->+  (U.DUP _vn, a ::& rs) -> workOnInstr uInstr $     pure (inp :/ DUP ::: (a ::& a::& rs))    (U.DUP _vn, SNil) -> notEnoughItemsOnStack -  (U.SWAP, a ::& b ::& rs) ->+  (U.SWAP, a ::& b ::& rs) -> workOnInstr uInstr $     pure (inp :/ SWAP ::: (b ::& a ::& rs))    (U.SWAP, _) -> notEnoughItemsOnStack -  (U.DIG nTotal, inputHST) ->+  (U.DIG nTotal, inputHST) -> workOnInstr uInstr $     go nTotal inputHST <&> \case       TCDigHelper s out -> inputHST :/ DIG s ::: out     where@@ -288,7 +364,7 @@         -> TypeCheckInstr (TCDigHelper inp)       go n i = case (n, i) of         -- Even 'DIG 0' is invalid on empty stack (so it is not strictly `Nop`).-        (_, SNil) -> notEnoughItemsOnStack+        (_, SNil) -> notEnoughItemsOnStack'          (0, (_ ::& _)) -> pure (TCDigHelper SZ i) @@ -296,7 +372,7 @@           go (n - 1) iTail <&> \case           TCDigHelper s (a ::& resTail) -> TCDigHelper (SS s) (a ::& b ::& resTail) -  (U.DUG nTotal, inputHST) ->+  (U.DUG nTotal, inputHST) -> workOnInstr uInstr $     go nTotal inputHST <&> \case       TCDugHelper s out -> inputHST :/ DUG s ::: out     where@@ -314,32 +390,32 @@         -- Two cases:         -- 1. Input stack is empty.         -- 2. n > 0 and input stack has exactly 1 item.-        _ -> notEnoughItemsOnStack+        _ -> notEnoughItemsOnStack' -  (U.PUSH vn mt mval, i) ->+  (U.PUSH vn mt mval, i) -> workOnInstr uInstr $     withUType mt $ \(nt :: Notes t) -> do       val <- typeCheckValue @t mval       proofScope <- onScopeCheckInstrErr @t uInstr (SomeHST i) Nothing         $ checkScope @(ConstantScope t)       case proofScope of-        Dict -> withWTPInstr @t $  pure $ i :/ PUSH val ::: ((nt, Dict, vn) ::& i)+        Dict -> withWTPInstr @t $ pure $ i :/ PUSH val ::: ((nt, Dict, vn) ::& i) -  (U.SOME tn vn, (an, Dict, _) ::& rs) -> do+  (U.SOME tn vn, (an, Dict, _) ::& rs) -> workOnInstr uInstr $     pure (inp :/ SOME ::: ((NTOption tn an, Dict, vn) ::& rs))    (U.SOME _ _, SNil) -> notEnoughItemsOnStack -  (U.NONE tn vn elMt, _) ->+  (U.NONE tn vn elMt, _) -> workOnInstr uInstr $     withUType elMt $ \(elNotes :: Notes t) ->       withWTPInstr @t $         pure $ inp :/ NONE ::: ((NTOption tn elNotes, Dict, vn) ::& inp) -  (U.UNIT tn vn, _) ->+  (U.UNIT tn vn, _) -> workOnInstr uInstr $     pure $ inp :/ UNIT ::: ((NTUnit tn, Dict, vn) ::& inp)    (U.IF_NONE mp mq, (STOption{}, (ons :: Notes ('TOption a)), Dict, ovn) ::&+ rs) -> do     let (an, avn) = deriveNsOption ons ovn-    withWTPInstr @a $+    withWTPInstr' @a $       genericIf IF_NONE U.IF_NONE mp mq rs ((an, Dict, avn) ::& rs) inp    (U.IF_NONE _ _, _ ::& _) ->@@ -347,7 +423,7 @@    (U.IF_NONE _ _, SNil) -> notEnoughItemsOnStack -  (U.PAIR tn vn pfn qfn, (an, _, avn) ::& (bn, _, bvn) ::& rs) -> do+  (U.PAIR tn vn pfn qfn, (an, _, avn) ::& (bn, _, bvn) ::& rs) -> workOnInstr uInstr $ do     let (vn', pfn', qfn') = deriveSpecialFNs pfn qfn avn bvn     case NTPair tn pfn' qfn' an bn of       (ns :: Notes ('TPair a b)) -> withWTPInstr @('TPair a b) $@@ -355,7 +431,7 @@    (U.PAIR {}, _) -> notEnoughItemsOnStack -  (U.CAR vn fn, (STPair{}, NTPair pairTN pfn qfn (pns :: Notes p) (qns :: Notes q), _, pairVN) ::&+ rs) -> do+  (U.CAR vn fn, (STPair{}, NTPair pairTN pfn qfn (pns :: Notes p) (qns :: Notes q), _, pairVN) ::&+ rs) -> workOnInstr uInstr $ do     pfn' <- onTypeCheckInstrAnnErr uInstr inp (Just CarArgument) (convergeAnns fn pfn)     withWTPInstr @p $       withWTPInstr @('TPair p q) $ do@@ -368,7 +444,7 @@    (U.CAR _ _, SNil) -> notEnoughItemsOnStack -  (U.CDR vn fn, (STPair{}, NTPair pairTN pfn qfn (pns :: Notes p) (qns :: Notes q), _, pairVN) ::&+ rs) -> do+  (U.CDR vn fn, (STPair{}, NTPair pairTN pfn qfn (pns :: Notes p) (qns :: Notes q), _, pairVN) ::&+ rs) -> workOnInstr uInstr $ do     qfn' <- onTypeCheckInstrAnnErr uInstr inp (Just CdrArgument) (convergeAnns fn qfn)      withWTPInstr @q $@@ -383,7 +459,7 @@   (U.CDR _ _, SNil) -> notEnoughItemsOnStack    (U.LEFT tn vn pfn qfn bMt, (an :: Notes l, Dict, _) ::& rs) ->-    withUType bMt $ \(bn :: Notes r) -> do+    withUType bMt $ \(bn :: Notes r) -> workOnInstr uInstr $ do       withWTPInstr @r $ do         let ns = NTOr tn pfn qfn an bn         pure (inp :/ LEFT ::: ((ns, Dict, vn) ::& rs))@@ -391,7 +467,7 @@   (U.LEFT {}, SNil) -> notEnoughItemsOnStack    (U.RIGHT tn vn pfn qfn aMt, (bn :: Notes r, Dict, _) ::& rs) ->-    withUType aMt $ \(an :: Notes l) -> do+    withUType aMt $ \(an :: Notes l) -> workOnInstr uInstr $ do       withWTPInstr @l $ do         let ns = NTOr tn pfn qfn an bn         pure (inp :/ RIGHT ::: ((ns, Dict, vn) ::& rs))@@ -401,8 +477,8 @@   (U.IF_LEFT mp mq, (STOr{}, ons, _, ovn) ::&+ rs) -> do     case deriveNsOr ons ovn of       (an :: Notes a, bn :: Notes b, avn, bvn) ->-        withWTPInstr @a $-          withWTPInstr @b $ do+        withWTPInstr' @a $+          withWTPInstr' @b $ do             let               ait = (an, Dict, avn) ::& rs               bit = (bn, Dict, bvn) ::& rs@@ -413,13 +489,13 @@    (U.IF_LEFT _ _, SNil) -> notEnoughItemsOnStack -  (U.NIL tn vn elMt, i) ->+  (U.NIL tn vn elMt, i) -> workOnInstr uInstr $     withUType elMt $ \(elNotes :: Notes t) ->       withWTPInstr @('TList t) $         pure $ i :/ NIL ::: ((NTList tn elNotes, Dict, vn) ::& i)    (U.CONS vn, ((an :: Notes a), _, _)-                ::& ((ln :: Notes l), _, _) ::& rs) ->+                ::& ((ln :: Notes l), _, _) ::& rs) -> workOnInstr uInstr     case eqType @('TList a) @l of       Right Refl -> do         (n :: Notes t) <- onTypeCheckInstrAnnErr uInstr inp (Just ConsArgument) (converge ln (NTList def an))@@ -431,8 +507,8 @@    (U.IF_CONS mp mq, (STList{}, ns, Dict, vn) ::&+ rs) -> do     case ns of-      NTList _ (an :: Notes t1) -> do-        ait <- withWTPInstr @t1 $ pure $ (an, Dict, vn <> "hd") ::& (ns, Dict, vn <> "tl") ::& rs+      NTList _ (an :: Notes t1) -> withWTPInstr' @t1 $ do+        let ait = (an, Dict, vn <> "hd") ::& (ns, Dict, vn <> "tl") ::& rs         genericIf IF_CONS U.IF_CONS mp mq ait rs inp    (U.IF_CONS _ _, _ ::& _) ->@@ -440,11 +516,11 @@    (U.IF_CONS _ _, SNil)-> notEnoughItemsOnStack -  (U.SIZE vn, (NTList{}, _, _) ::& _) -> sizeImpl inp vn-  (U.SIZE vn, (NTSet{}, _, _) ::& _) -> sizeImpl inp vn-  (U.SIZE vn, (NTMap{}, _, _) ::& _) -> sizeImpl inp vn-  (U.SIZE vn, (NTString{}, _, _) ::& _) -> sizeImpl inp vn-  (U.SIZE vn, (NTBytes{}, _, _) ::& _) -> sizeImpl inp vn+  (U.SIZE vn, (NTList{}, _, _) ::& _) -> workOnInstr uInstr $ sizeImpl inp vn+  (U.SIZE vn, (NTSet{}, _, _) ::& _) -> workOnInstr uInstr $ sizeImpl inp vn+  (U.SIZE vn, (NTMap{}, _, _) ::& _) -> workOnInstr uInstr $ sizeImpl inp vn+  (U.SIZE vn, (NTString{}, _, _) ::& _) -> workOnInstr uInstr $ sizeImpl inp vn+  (U.SIZE vn, (NTBytes{}, _, _) ::& _) -> workOnInstr uInstr $ sizeImpl inp vn   (U.SIZE _, _ ::& _) ->     failWithErr $ UnexpectedType       $ (ExpectList Nothing :| []) :|@@ -456,33 +532,33 @@    (U.SIZE _, SNil) -> notEnoughItemsOnStack -  (U.EMPTY_SET tn vn mv, i) ->+  (U.EMPTY_SET tn vn mv, i) -> workOnInstr uInstr $     withUType mv $ \(vns :: Notes v) ->       withWTPInstr @('TSet v) $         withCompareableCheck (notesSing vns) uInstr inp $ i :/ EMPTY_SET ::: ((STSet sing, NTSet tn vns, Dict, vn) ::&+ i) -  (U.EMPTY_MAP tn vn mk mv, i) -> do+  (U.EMPTY_MAP tn vn mk mv, i) -> workOnInstr uInstr $ do     withUType mv $ \(vns :: Notes v)  ->       withUType mk $ \(ktn :: Notes k) ->         withWTPInstr @('TMap k v) $           withCompareableCheck (notesSing ktn) uInstr inp $ i :/ EMPTY_MAP ::: ((STMap sing sing, NTMap tn ktn vns, Dict, vn) ::&+ i) -  (U.EMPTY_BIG_MAP tn vn mk mv, i) ->+  (U.EMPTY_BIG_MAP tn vn mk mv, i) -> workOnInstr uInstr $     withUType mv $ \(vns :: Notes v)  ->       withUType mk $ \(ktn :: Notes k) ->         withWTPInstr @('TBigMap k v) $           withCompareableCheck (notesSing ktn) uInstr inp $ i :/ EMPTY_BIG_MAP ::: ((STBigMap sing sing, NTBigMap tn ktn vns, Dict, vn) ::&+ i)    (U.MAP vn mp, (STList _, NTList _ (vns :: Notes t1), Dict, _vn) ::&+ _) -> do-    withWTPInstr @t1 $-      mapImpl vns uInstr mp inp+    withWTPInstr' @t1 $+      mapImpl (U.MAP vn) vns uInstr mp inp         (\(rn :: Notes t) hst -> withWTPInstr @t $ pure $  (NTList def rn, Dict, vn) ::& hst)    (U.MAP vn mp, (STMap{}, NTMap _ kns vns, Dict, _vn) ::&+ _) -> do     case NTPair def def def kns vns of       (pns :: Notes ('TPair k v1)) ->-        withWTPInstr @('TPair k v1) $-          mapImpl pns uInstr mp inp+        withWTPInstr' @('TPair k v1) $+          mapImpl (U.MAP vn) pns uInstr mp inp              (\(rn :: Notes v) hst -> withWTPInstr @('TMap k v) $ pure $ (NTMap def kns rn, Dict, vn) ::& hst)    (U.MAP _ _, _ ::& _) ->@@ -494,17 +570,17 @@   (U.MAP _ _, SNil) -> notEnoughItemsOnStack    (U.ITER is, (STSet (_ :: Sing t1), NTSet _ en, _, _) ::&+ _) -> do-    withWTPInstr @t1 $+    withWTPInstr' @t1 $       iterImpl en uInstr is inp    (U.ITER is, (STList (_ :: Sing t1), NTList _ en, _, _) ::&+ _) -> do-    withWTPInstr @t1 $+    withWTPInstr' @t1 $       iterImpl en uInstr is inp    (U.ITER is, (STMap _ _, NTMap _ kns vns, _, _) ::&+ _) -> do     case NTPair def def def kns vns of       (en :: Notes ('TPair a b)) ->-        withWTPInstr @('TPair a b) $ iterImpl en uInstr is inp+        withWTPInstr' @('TPair a b) $ iterImpl en uInstr is inp    (U.ITER _, _ ::& _) ->     failWithErr $ UnexpectedType@@ -516,13 +592,13 @@   (U.ITER _, SNil) -> notEnoughItemsOnStack    (U.MEM varNotes,-   _ ::& (STSet{}, NTSet _ notesK, _, _) ::&+ _) ->+   _ ::& (STSet{}, NTSet _ notesK, _, _) ::&+ _) -> workOnInstr uInstr $     memImpl notesK inp varNotes   (U.MEM varNotes,-   _ ::& (STMap{}, NTMap _ notesK _, _, _) ::&+ _) ->+   _ ::& (STMap{}, NTMap _ notesK _, _, _) ::&+ _) -> workOnInstr uInstr $     memImpl notesK inp varNotes   (U.MEM varNotes,-   _ ::& (STBigMap{}, NTBigMap _ notesK _, _, _) ::&+ _) ->+   _ ::& (STBigMap{}, NTBigMap _ notesK _, _, _) ::&+ _) -> workOnInstr uInstr $     memImpl notesK inp varNotes   (U.MEM _, _ ::& _ ::& _) ->     failWithErr $ UnexpectedType@@ -536,10 +612,12 @@    (U.GET varNotes,    _ ::& (STMap{}, NTMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->-    withWTPInstr @v $ getImpl notesK inp notesV varNotes+    workOnInstr uInstr $ withWTPInstr @v $+      getImpl notesK inp notesV varNotes   (U.GET varNotes,    _ ::& (STBigMap{}, NTBigMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->-    withWTPInstr @v $ getImpl notesK inp notesV varNotes+    workOnInstr uInstr $ withWTPInstr @v $+      getImpl notesK inp notesV varNotes    (U.GET _, _ ::& _ ::& _) ->     failWithErr $ UnexpectedType@@ -551,13 +629,13 @@    (U.UPDATE varNotes,    _ ::& _ ::& (STMap{}, (NTMap _ notesK (notesV :: Notes v)), _, _) ::&+ _) ->-    updImpl notesK inp (NTOption U.noAnn notesV) varNotes+    workOnInstr uInstr $ updImpl notesK inp (NTOption U.noAnn notesV) varNotes   (U.UPDATE varNotes,    _ ::& _ ::& (STBigMap{}, NTBigMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->-    updImpl notesK inp (NTOption U.noAnn notesV) varNotes+    workOnInstr uInstr $ updImpl notesK inp (NTOption U.noAnn notesV) varNotes   (U.UPDATE varNotes,    _ ::& _ ::& (STSet{}, NTSet _ (notesK :: Notes k), _, _) ::&+ _) ->-    updImpl notesK inp (NTBool U.noAnn) varNotes+    workOnInstr uInstr $ updImpl notesK inp (NTBool U.noAnn) varNotes    (U.UPDATE _, _ ::& _ ::& _ ::& _) ->     failWithErr $ UnexpectedType@@ -577,16 +655,16 @@   (U.IF _ _, SNil) -> notEnoughItemsOnStack    (U.LOOP is, (NTBool{}, _, _) ::& (rs :: HST rs)) -> do-    _ :/ tp <- lift $ typeCheckList is rs-    case tp of-      subI ::: (o :: HST o) -> do-        case eqHST o (sing @('TBool) -:& rs) of-          Right Refl -> do-            let _ ::& rs' = o-            pure $ inp :/ LOOP subI ::: rs'-          Left m -> typeCheckInstrErr' uInstr (SomeHST inp) (Just Iteration) m-      AnyOutInstr subI ->-        pure $ inp :/ LOOP subI ::: rs+    preserving (tcList is rs) U.LOOP $ \(_ :/ tp) ->+      case tp of+        subI ::: (o :: HST o) -> do+          case eqHST o (sing @('TBool) -:& rs) of+            Right Refl -> do+              let _ ::& rs' = o+              pure $ inp :/ LOOP subI ::: rs'+            Left m -> typeCheckInstrErr' uInstr (SomeHST inp) (Just Iteration) m+        AnyOutInstr subI ->+          pure $ inp :/ LOOP subI ::: rs    (U.LOOP _, _ ::& _ ::& _) ->     failWithErr $ UnexpectedType@@ -597,22 +675,22 @@   (U.LOOP_LEFT is, (os@STOr{}, ons, Dict, ovn) ::&+ rs) -> do     case deriveNsOr ons ovn of       (an :: Notes t, bn :: Notes b, avn, bvn) -> do-        withWTPInstr @t $ withWTPInstr @b $ do+        withWTPInstr' @t $ withWTPInstr' @b $ do           let ait = (an, Dict, avn) ::& rs-          _ :/ tp <- lift $ typeCheckList is ait-          case tp of-            subI ::: o -> do-              case (eqHST o (os -:& rs), o) of-                (Right Refl, ((ons', Dict, ovn') ::& rs')) -> do-                    let (_, bn', _, bvn') = deriveNsOr ons' ovn'-                    br <- onTypeCheckInstrAnnErr uInstr inp-                            (Just Iteration)-                            (convergeHSTEl (bn, Dict, bvn) (bn', Dict, bvn'))-                    pure $ inp :/ LOOP_LEFT subI ::: (br ::& rs')-                (Left m, _) -> typeCheckInstrErr' uInstr (SomeHST inp) (Just Iteration) m-            AnyOutInstr subI -> do-              let br = (bn, Dict, bvn)-              pure $ inp :/ LOOP_LEFT subI ::: (br ::& rs)+          preserving (tcList is ait) U.LOOP_LEFT $ \(_ :/ tp) ->+            case tp of+              subI ::: o -> do+                case (eqHST o (os -:& rs), o) of+                  (Right Refl, ((ons', Dict, ovn') ::& rs')) -> do+                      let (_, bn', _, bvn') = deriveNsOr ons' ovn'+                      br <- onTypeCheckInstrAnnErr uInstr inp+                              (Just Iteration)+                              (convergeHSTEl (bn, Dict, bvn) (bn', Dict, bvn'))+                      pure $ inp :/ LOOP_LEFT subI ::: (br ::& rs')+                  (Left m, _) -> typeCheckInstrErr' uInstr (SomeHST inp) (Just Iteration) m+              AnyOutInstr subI -> do+                let br = (bn, Dict, bvn)+                pure $ inp :/ LOOP_LEFT subI ::: (br ::& rs)    (U.LOOP_LEFT _, _ ::& _) ->     failWithErr $ UnexpectedType@@ -620,12 +698,12 @@    (U.LOOP_LEFT _, _) -> notEnoughItemsOnStack -  (U.LAMBDA vn (AsUType (ins :: Notes t)) (AsUType (ons :: Notes u)) is, i) -> do+  (U.LAMBDA vn p1@(AsUType (ins :: Notes t)) p2@(AsUType (ons :: Notes u)) is, i) -> do     -- further processing is extracted into another function just not to     -- litter our main typechecking logic-    withWTPInstr @t $-      withWTPInstr @u $-        lamImpl uInstr is vn ins ons i+    withWTPInstr' @t $+      withWTPInstr' @u $+        lamImpl (U.LAMBDA vn p1 p2) uInstr is vn ins ons i    (U.EXEC vn, ((_ :: Notes t1), _, _)                               ::& ( STLambda _ _@@ -633,7 +711,7 @@                                   , _                                   , _                                   )-                              ::&+ rs) -> do+                              ::&+ rs) -> workOnInstr uInstr $ do     Refl <- onTypeCheckInstrErr uInstr (SomeHST inp) (Just LambdaArgument)                   (eqType @t1 @t1')     withWTPInstr @t2' $ pure $ inp :/ EXEC ::: ((t2n, Dict, vn) ::& rs)@@ -649,7 +727,7 @@                       , NTLambda vann (NTPair _ _ _ (_ :: Notes a) (nb :: Notes b)) sc                       , _                       , _)-                  ::&+ rs) -> do+                  ::&+ rs) -> workOnInstr uInstr $ do     case NTLambda vann nb sc of       (l2n :: Notes ('TLambda t1 t2)) -> withWTPInstr @('TLambda t1 t2) $ do @@ -668,48 +746,57 @@   (U.APPLY _, _) -> notEnoughItemsOnStack    (U.DIP is, a ::& s) -> do-    typeCheckDipBody uInstr is s $-      \subI t -> pure $ inp :/ DIP subI ::: (a ::& t)+    typeCheckDipBody U.DIP uInstr is s+      (IllTypedSeq)+      (\subI t -> WellTypedSeq $ inp :/ DIP subI ::: (a ::& t))    (U.DIP _is, SNil) -> notEnoughItemsOnStack    (U.DIPN nTotal instructions, inputHST) ->     go nTotal inputHST <&> \case-    TCDipHelper s subI out -> inputHST :/ DIPN s subI ::: out+      TCDipHelperErr err rest -> IllTypedSeq err rest+      TCDipHelperOk s subI out -> WellTypedSeq $ inputHST :/ DIPN s subI ::: out     where       go :: forall inp. Typeable inp         => Word         -> HST inp-        -> TypeCheckInstr (TCDipHelper inp)+        -> TypeCheckInstrNoExcept (TCDipHelper inp)       go n curHST = case (n, curHST) of-        (0, _) -> typeCheckDipBody uInstr instructions curHST $ \subI t ->-          pure (TCDipHelper SZ subI t)-        (_, SNil) -> notEnoughItemsOnStack+        (0, _) -> typeCheckDipBody (U.DIPN nTotal) uInstr instructions curHST+          (TCDipHelperErr)+          (TCDipHelperOk SZ)+        (_, SNil) -> do+          pos <- ask+          let err = TCFailedOnInstr uInstr (SomeHST inp) pos Nothing (Just NotEnoughItemsOnStack)+          pure $ TCDipHelperErr err [NonTypedInstr $ U.PrimEx uInstr]         (_, hstHead ::& hstTail) ->           go (n - 1) hstTail <&> \case-          TCDipHelper s subI out -> TCDipHelper (SS s) subI (hstHead ::& out)+          TCDipHelperOk s subI out -> TCDipHelperOk (SS s) subI (hstHead ::& out)+          TCDipHelperErr err rest -> TCDipHelperErr err rest+   (u, v) -> case (u, v) of -- Workaround for not exceeding -fmax-pmcheck-iterations limit-    (U.FAILWITH, (_ ::& _)) ->+    (U.FAILWITH, (_ ::& _)) -> workOnInstr uInstr $       pure $ inp :/ AnyOutInstr FAILWITH      (U.FAILWITH, _) -> notEnoughItemsOnStack -    (U.CAST vn (AsUType (castToNotes :: Notes t)), (en, _, evn) ::& rs) -> do-      (Refl, _) <- errM $ matchTypes en castToNotes-      withWTPInstr @t $-        pure $ inp :/ CAST ::: ((castToNotes, Dict, vn `orAnn` evn) ::& rs)+    (U.CAST vn (AsUType (castToNotes :: Notes t)), (en, _, evn) ::& rs) ->+      workOnInstr uInstr $ do+        (Refl, _) <- errM $ matchTypes en castToNotes+        withWTPInstr @t $+          pure $ inp :/ CAST ::: ((castToNotes, Dict, vn `orAnn` evn) ::& rs)       where         errM :: (MonadReader InstrCallStack m, MonadError TCError m) => Either TCTypeError a -> m a         errM = onTypeCheckInstrErr uInstr (SomeHST inp) (Just Cast)      (U.CAST _ _, _) -> notEnoughItemsOnStack -    (U.RENAME vn, (an, Dict, _) ::& rs) ->+    (U.RENAME vn, (an, Dict, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ RENAME ::: ((an, Dict, vn) ::& rs)      (U.RENAME _, SNil) -> notEnoughItemsOnStack -    (U.UNPACK tn vn mt, (NTBytes{}, _, _) ::& rs) ->+    (U.UNPACK tn vn mt, (NTBytes{}, _, _) ::& rs) -> workOnInstr uInstr $       withUType mt $ \(tns :: Notes tn) -> do         case NTOption tn tns of           (ns :: Notes ('TOption t1)) -> withWTPInstr @('TOption t1) $ do@@ -722,7 +809,7 @@      (U.UNPACK {}, SNil) -> notEnoughItemsOnStack -    (U.PACK vn, (_ :: Notes a, _, _) ::& rs) -> do+    (U.PACK vn, (_ :: Notes a, _, _) ::& rs) -> workOnInstr uInstr $ do       Dict <- onScopeCheckInstrErr @a uInstr (SomeHST inp) Nothing         $ checkScope @(PackedValScope a)       pure $ inp :/ PACK ::: ((starNotes, Dict, vn) ::& rs)@@ -730,13 +817,13 @@     (U.PACK _, SNil) -> notEnoughItemsOnStack      (U.CONCAT vn, (NTBytes{}, _, _) ::& (NTBytes{}, _, _) ::& _) ->-      concatImpl inp vn+      workOnInstr uInstr $ concatImpl inp vn     (U.CONCAT vn, (NTString{}, _, _) ::& (NTString{}, _, _) ::& _) ->-      concatImpl inp vn+      workOnInstr uInstr $ concatImpl inp vn     (U.CONCAT vn, (STList STBytes, _, _, _) ::&+ _) ->-      concatImpl' inp vn+      workOnInstr uInstr $ concatImpl' inp vn     (U.CONCAT vn, (STList STString, _, _, _) ::&+ _) ->-      concatImpl' inp vn+      workOnInstr uInstr $ concatImpl' inp vn     (U.CONCAT _, _ ::& _ ::& _) ->       failWithErr $ UnexpectedType         $ (ExpectByte :| [ExpectByte]) :|@@ -751,10 +838,10 @@      (U.SLICE vn, (NTNat{}, _, _) ::&                  (NTNat{}, _, _) ::&-                 (NTString{}, _, _) ::& _) -> sliceImpl inp vn+                 (NTString{}, _, _) ::& _) -> workOnInstr uInstr $ sliceImpl inp vn     (U.SLICE vn, (NTNat{}, _, _) ::&                  (NTNat{}, _, _) ::&-                 (NTBytes{}, _, _) ::& _) -> sliceImpl inp vn+                 (NTBytes{}, _, _) ::& _) -> workOnInstr uInstr $ sliceImpl inp vn      (U.SLICE _, _ ::& _ ::& _ ::& _) ->       failWithErr $ UnexpectedType@@ -763,7 +850,7 @@         ]     (U.SLICE _, _) -> notEnoughItemsOnStack -    (U.ISNAT vn', (NTInt{}, _, oldVn) ::& rs) -> do+    (U.ISNAT vn', (NTInt{}, _, oldVn) ::& rs) -> workOnInstr uInstr $ do       let vn = vn' `orAnn` oldVn       pure $ inp :/ ISNAT ::: ((starNotes, Dict, vn) ::& rs) @@ -773,30 +860,37 @@     (U.ISNAT _, SNil)-> notEnoughItemsOnStack      -- Type checking is already done inside `addImpl`.-    (U.ADD vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> addImpl a b inp vn uInstr+    (U.ADD vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> workOnInstr uInstr $+      addImpl a b inp vn uInstr      (U.ADD _, _) -> notEnoughItemsOnStack -    (U.SUB vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> subImpl a b inp vn uInstr+    (U.SUB vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> workOnInstr uInstr $+      subImpl a b inp vn uInstr      (U.SUB _, _) -> notEnoughItemsOnStack -    (U.MUL vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> mulImpl a b inp vn uInstr+    (U.MUL vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> workOnInstr uInstr $+      mulImpl a b inp vn uInstr      (U.MUL _, _) -> notEnoughItemsOnStack -    (U.EDIV vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> edivImpl a b inp vn uInstr+    (U.EDIV vn, (a, _, _, _) ::&+ (b, _, _, _) ::&+ _) -> workOnInstr uInstr $+      edivImpl a b inp vn uInstr      (U.EDIV _, _) -> notEnoughItemsOnStack -    (U.ABS vn, (STInt, _, _, _) ::&+ _) -> unaryArithImpl @Abs ABS inp vn+    (U.ABS vn, (STInt, _, _, _) ::&+ _) -> workOnInstr uInstr $+      unaryArithImpl @Abs ABS inp vn     (U.ABS _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectInt :| []) :| []      (U.ABS _, SNil) -> notEnoughItemsOnStack -    (U.NEG vn, (STInt, _, _, _) ::&+ _) -> unaryArithImpl @Neg NEG inp vn-    (U.NEG vn, (STNat, _, _, _) ::&+ _) -> unaryArithImpl @Neg NEG inp vn+    (U.NEG vn, (STInt, _, _, _) ::&+ _) -> workOnInstr uInstr $+      unaryArithImpl @Neg NEG inp vn+    (U.NEG vn, (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      unaryArithImpl @Neg NEG inp vn     (U.NEG _, _ ::& _) ->       failWithErr $ UnexpectedType         $ (ExpectInt :| []) :|@@ -805,21 +899,25 @@     (U.NEG _, SNil) -> notEnoughItemsOnStack      (U.LSL vn, (STNat, _, _, _) ::&+-               (STNat, _, _, _) ::&+ _) -> arithImpl @Lsl LSL inp vn uInstr+               (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @Lsl LSL inp vn uInstr     (U.LSL _, _ ::& _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectNat :| [ExpectNat]) :| []     (U.LSL _, _) -> notEnoughItemsOnStack      (U.LSR vn, (STNat, _, _, _) ::&+-               (STNat, _, _, _) ::&+ _) -> arithImpl @Lsr LSR inp vn uInstr+               (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @Lsr LSR inp vn uInstr     (U.LSR _, _ ::& _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectNat :| [ExpectNat]) :| []     (U.LSR _, _) -> notEnoughItemsOnStack      (U.OR vn, (STBool, _, _, _) ::&+-              (STBool, _, _, _) ::&+ _) -> arithImpl @Or OR inp vn uInstr+              (STBool, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @Or OR inp vn uInstr     (U.OR vn, (STNat, _, _, _) ::&+-              (STNat, _, _, _) ::&+ _) -> arithImpl @Or OR inp vn uInstr+              (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @Or OR inp vn uInstr     (U.OR _, _ ::& _ ::& _) ->       failWithErr $ UnexpectedType         $ (ExpectBool :| [ExpectBool]) :|@@ -828,11 +926,14 @@     (U.OR _, _) -> notEnoughItemsOnStack      (U.AND vn, (STInt, _, _, _) ::&+-               (STNat, _, _, _) ::&+ _) -> arithImpl @And AND inp vn uInstr+               (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @And AND inp vn uInstr     (U.AND vn, (STNat, _, _, _) ::&+-               (STNat, _, _, _) ::&+ _) -> arithImpl @And AND inp vn uInstr+               (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @And AND inp vn uInstr     (U.AND vn, (STBool, _, _, _) ::&+-               (STBool, _, _, _) ::&+ _) -> arithImpl @And AND inp vn uInstr+               (STBool, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @And AND inp vn uInstr     (U.AND _, _ ::& _ ::& _) ->       failWithErr $ UnexpectedType         $ (ExpectInt :| [ExpectNat]) :|@@ -842,9 +943,11 @@     (U.AND _, _) -> notEnoughItemsOnStack      (U.XOR vn, (STBool, _, _, _) ::&+-               (STBool, _, _, _) ::&+ _) -> arithImpl @Xor XOR inp vn uInstr+               (STBool, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @Xor XOR inp vn uInstr     (U.XOR vn, (STNat, _, _, _) ::&+-               (STNat, _, _, _) ::&+ _) -> arithImpl @Xor XOR inp vn uInstr+               (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      arithImpl @Xor XOR inp vn uInstr     (U.XOR _, _ ::& _ ::& _) ->       failWithErr $ UnexpectedType         $ (ExpectBool :| [ExpectBool]) :|@@ -852,9 +955,12 @@         ]     (U.XOR _, _) -> notEnoughItemsOnStack -    (U.NOT vn, (STNat, _, _, _) ::&+ _) -> unaryArithImpl @Not NOT inp vn-    (U.NOT vn, (STBool, _, _, _) ::&+ _) -> unaryArithImpl @Not NOT inp vn-    (U.NOT vn, (STInt, _, _, _) ::&+ _) -> unaryArithImpl @Not NOT inp vn+    (U.NOT vn, (STNat, _, _, _) ::&+ _) -> workOnInstr uInstr $+      unaryArithImpl @Not NOT inp vn+    (U.NOT vn, (STBool, _, _, _) ::&+ _) -> workOnInstr uInstr $+      unaryArithImpl @Not NOT inp vn+    (U.NOT vn, (STInt, _, _, _) ::&+ _) -> workOnInstr uInstr $+      unaryArithImpl @Not NOT inp vn     (U.NOT _, _ ::& _) ->       failWithErr $ UnexpectedType         $ (ExpectNat :| []) :|@@ -868,7 +974,7 @@       ::& (bn :: Notes bT, _, _)       ::& rs       )-      -> do+      -> workOnInstr uInstr $ do       case eqType @aT @bT of         Right Refl -> do           void . errConv $ converge an bn@@ -886,43 +992,49 @@      (U.COMPARE _, _) -> notEnoughItemsOnStack -    (U.EQ vn, (NTInt{}, _, _) ::& _) -> unaryArithImpl @Eq' EQ inp vn+    (U.EQ vn, (NTInt{}, _, _) ::& _) -> workOnInstr uInstr $+      unaryArithImpl @Eq' EQ inp vn     (U.EQ _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectInt :| []) :| []     (U.EQ _, SNil) -> notEnoughItemsOnStack -    (U.NEQ vn, (NTInt{}, _, _) ::& _) -> unaryArithImpl @Neq NEQ inp vn+    (U.NEQ vn, (NTInt{}, _, _) ::& _) -> workOnInstr uInstr $+      unaryArithImpl @Neq NEQ inp vn     (U.NEQ _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectInt :| []) :| []     (U.NEQ _, SNil) -> notEnoughItemsOnStack -    (U.LT vn, (NTInt{}, _, _) ::& _) -> unaryArithImpl @Lt LT inp vn+    (U.LT vn, (NTInt{}, _, _) ::& _) -> workOnInstr uInstr $+      unaryArithImpl @Lt LT inp vn     (U.LT _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectInt :| []) :| []     (U.LT _, SNil) -> notEnoughItemsOnStack -    (U.GT vn, (NTInt{}, _, _) ::& _) -> unaryArithImpl @Gt GT inp vn+    (U.GT vn, (NTInt{}, _, _) ::& _) -> workOnInstr uInstr $+      unaryArithImpl @Gt GT inp vn     (U.GT _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectInt :| []) :| []     (U.GT _, SNil) -> notEnoughItemsOnStack -    (U.LE vn, (NTInt{}, _, _) ::& _) -> unaryArithImpl @Le LE inp vn+    (U.LE vn, (NTInt{}, _, _) ::& _) -> workOnInstr uInstr $+      unaryArithImpl @Le LE inp vn     (U.LE _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectInt :| []) :| []     (U.LE _, SNil) -> notEnoughItemsOnStack -    (U.GE vn, (NTInt{}, _, _) ::& _) -> unaryArithImpl @Ge GE inp vn+    (U.GE vn, (NTInt{}, _, _) ::& _) -> workOnInstr uInstr $+      unaryArithImpl @Ge GE inp vn     (U.GE _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectInt :| []) :| []     (U.GE _, SNil) -> notEnoughItemsOnStack -    (U.INT vn, (NTNat{}, _, _) ::& rs) ->+    (U.INT vn, (NTNat{}, _, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ INT ::: ((starNotes, Dict, vn) ::& rs)     (U.INT _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectNat :| []) :| []     (U.INT _, SNil) -> notEnoughItemsOnStack -    (U.SELF vn fn, _) -> do+    (U.SELF vn fn, _) -> workOnInstr uInstr $ do       mode <- gets tcMode       case mode of         TypeCheckValue (value, ty) ->@@ -942,7 +1054,7 @@           error "'SELF' appears in test typechecking."         TypeCheckPack ->           error "'SELF' appears in packed data."-    (U.CONTRACT vn fn mt, (NTAddress{}, _, _) ::& rs) ->+    (U.CONTRACT vn fn mt, (NTAddress{}, _, _) ::& rs) -> workOnInstr uInstr $       withUType mt $ \(tns :: Notes t) -> do         proofScope <- onScopeCheckInstrErr @t uInstr (SomeHST inp) (Just ContractParameter)           $ checkScope @(ParameterScope t)@@ -959,7 +1071,7 @@      (U.TRANSFER_TOKENS vn, ((_ :: Notes p'), _, _)       ::& (NTMutez{}, _, _)-      ::& (STContract (_ :: Sing p), _, _, _) ::&+ rs) -> do+      ::& (STContract (_ :: Sing p), _, _, _) ::&+ rs) -> workOnInstr uInstr $ do       proofScope <- onScopeCheckInstrErr @p uInstr (SomeHST inp) (Just ContractParameter)         $ checkScope @(ParameterScope p)       case (eqType @p @p', proofScope) of@@ -975,7 +1087,7 @@      (U.SET_DELEGATE vn,       (STOption STKeyHash, NTOption _ NTKeyHash{}, _, _)-      ::&+ rs) -> do+      ::&+ rs) -> workOnInstr uInstr $ do         pure $ inp :/ SET_DELEGATE ::: ((starNotes, Dict, vn) ::& rs)      (U.SET_DELEGATE _,  _ ::& _) ->@@ -986,7 +1098,7 @@     (U.CREATE_CONTRACT ovn avn contract,       (STOption STKeyHash, NTOption _ (_ :: Notes ('TKeyHash)), _, _)       ::&+ (NTMutez{}, _, _)-      ::& (gn :: Notes g, Dict, _) ::& rs) -> do+      ::& (gn :: Notes g, Dict, _) ::& rs) -> workOnInstr uInstr $ do         (SomeContract           (Contract             (contr :: ContractCode p' g')@@ -1006,69 +1118,70 @@      (U.CREATE_CONTRACT {},  _) -> notEnoughItemsOnStack -    (U.IMPLICIT_ACCOUNT vn, (NTKeyHash{}, _, _) ::& rs) ->+    (U.IMPLICIT_ACCOUNT vn, (NTKeyHash{}, _, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ IMPLICIT_ACCOUNT ::: ((starNotes, Dict, vn) ::& rs)      (U.IMPLICIT_ACCOUNT _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectKeyHash :| []) :| []     (U.IMPLICIT_ACCOUNT _, SNil) -> notEnoughItemsOnStack -    (U.NOW vn, _) ->+    (U.NOW vn, _) -> workOnInstr uInstr $       pure $ inp :/ NOW ::: ((starNotes, Dict, vn) ::& inp) -    (U.AMOUNT vn, _) ->+    (U.AMOUNT vn, _) -> workOnInstr uInstr $       pure $ inp :/ AMOUNT ::: ((starNotes, Dict, vn) ::& inp) -    (U.BALANCE vn, _) ->+    (U.BALANCE vn, _) -> workOnInstr uInstr $       pure $ inp :/ BALANCE ::: ((starNotes, Dict, vn) ::& inp)      (U.CHECK_SIGNATURE vn,                (NTKey _, _, _)                ::& (NTSignature _, _, _) ::& (NTBytes{}, _, _) ::& rs) ->-      pure $ inp :/ CHECK_SIGNATURE ::: ((starNotes, Dict, vn) ::& rs)+      workOnInstr uInstr $+        pure $ inp :/ CHECK_SIGNATURE ::: ((starNotes, Dict, vn) ::& rs)      (U.CHECK_SIGNATURE _, _ ::& _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectKey :| [ExpectSignature]) :| []     (U.CHECK_SIGNATURE _, _) -> notEnoughItemsOnStack -    (U.SHA256 vn, (NTBytes{}, _, _) ::& rs) ->+    (U.SHA256 vn, (NTBytes{}, _, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ SHA256 ::: ((starNotes, Dict, vn) ::& rs)     (U.SHA256 _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectByte :| []) :| []     (U.SHA256 _, SNil) -> notEnoughItemsOnStack -    (U.SHA512 vn, (NTBytes{}, _, _) ::& rs) ->+    (U.SHA512 vn, (NTBytes{}, _, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ SHA512 ::: ((starNotes, Dict, vn) ::& rs)     (U.SHA512 _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectByte :| []) :| []     (U.SHA512 _, SNil) -> notEnoughItemsOnStack -    (U.BLAKE2B vn, (NTBytes{}, _, _) ::& rs) ->+    (U.BLAKE2B vn, (NTBytes{}, _, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ BLAKE2B ::: ((starNotes, Dict, vn) ::& rs)     (U.BLAKE2B _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectByte :| []) :| []     (U.BLAKE2B _, SNil) -> notEnoughItemsOnStack -    (U.HASH_KEY vn, (NTKey{}, _, _) ::& rs) ->+    (U.HASH_KEY vn, (NTKey{}, _, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ HASH_KEY ::: ((starNotes, Dict, vn) ::& rs)     (U.HASH_KEY _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectKey :| []) :| []     (U.HASH_KEY _, SNil) -> notEnoughItemsOnStack -    (U.SOURCE vn, _) ->+    (U.SOURCE vn, _) -> workOnInstr uInstr $       pure $ inp :/ SOURCE ::: ((starNotes, Dict, vn) ::& inp) -    (U.SENDER vn, _) ->+    (U.SENDER vn, _) -> workOnInstr uInstr $       pure $ inp :/ SENDER ::: ((starNotes, Dict, vn) ::& inp) -    (U.ADDRESS vn, (NTContract{}, _, _) ::& rs) ->+    (U.ADDRESS vn, (NTContract{}, _, _) ::& rs) -> workOnInstr uInstr $       pure $ inp :/ ADDRESS ::: ((starNotes, Dict, vn) ::& rs)      (U.ADDRESS _, _ ::& _) ->       failWithErr $ UnexpectedType $ (ExpectContract :| []) :| []     (U.ADDRESS _, SNil) -> notEnoughItemsOnStack -    (U.CHAIN_ID vn, _) ->+    (U.CHAIN_ID vn, _) -> workOnInstr uInstr $       pure $ inp :/ CHAIN_ID ::: ((starNotes, Dict, vn) ::& inp)      -- Could not get rid of the catch all clause due to this warning:@@ -1080,15 +1193,25 @@     i ->       error $ "Pattern matches should be exhuastive, but instead got: " <> show i   where-    withWTPInstr :: forall t a. SingI t => (WellTyped t => TypeCheckInstr a) -> TypeCheckInstr a-    withWTPInstr fn = withWTPInstr_ @t uInstr (SomeHST inp) fn+    withWTPInstr'+      :: forall t inp. SingI t+      => (WellTyped t => TypeCheckInstrNoExcept (TypeCheckedSeq inp))+      -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+    withWTPInstr' = withWTPInstr'_ @t uInstr (SomeHST inp) -    failWithErr :: (MonadReader InstrCallStack m, MonadError TCError m) => TCTypeError -> m a-    failWithErr = typeCheckInstrErr' uInstr (SomeHST inp) Nothing+    withWTPInstr+      :: forall t a. SingI t => (WellTyped t => TypeCheckInstr a) -> TypeCheckInstr a+    withWTPInstr = withWTPInstr_ @t uInstr (SomeHST inp) -    notEnoughItemsOnStack :: (MonadReader InstrCallStack m, MonadError TCError m) => m a+    failWithErr :: TCTypeError -> TypeCheckInstrNoExcept (TypeCheckedSeq a)+    failWithErr = workOnInstr uInstr . typeCheckInstrErr' uInstr (SomeHST inp) Nothing++    notEnoughItemsOnStack :: TypeCheckInstrNoExcept (TypeCheckedSeq a)     notEnoughItemsOnStack = failWithErr NotEnoughItemsOnStack +    notEnoughItemsOnStack' :: TypeCheckInstr a+    notEnoughItemsOnStack' = typeCheckInstrErr' uInstr (SomeHST inp) Nothing NotEnoughItemsOnStack+ -- | Helper function for two-branch if where each branch is given a single -- value. genericIf@@ -1099,29 +1222,31 @@         Instr bfi s' ->         Instr (cond ': rs) s'      )-  -> ([U.ExpandedOp] -> [U.ExpandedOp] -> U.ExpandedInstr)+  -> (forall op. [op] -> [op] -> U.InstrAbstract op)   -> [U.ExpandedOp]   -> [U.ExpandedOp]   -> HST bti   -> HST bfi   -> HST (cond ': rs)-  -> TypeCheckInstr (SomeInstr (cond ': rs))+  -> TypeCheckInstrNoExcept (TypeCheckedSeq (cond ': rs)) genericIf cons mCons mbt mbf bti bfi i@(_ ::& _) = do-  _ :/ pinstr <- lift $ typeCheckList mbt bti-  _ :/ qinstr <- lift $ typeCheckList mbf bfi-  fmap (i :/) $ case (pinstr, qinstr) of-    (p ::: po, q ::: qo) -> do-      let instr = mCons mbt mbf-      Refl <- onTypeCheckInstrErr instr (SomeHST i) (Just If)-        $ eqHST po qo-      o <- onTypeCheckInstrAnnErr instr i (Just If) (convergeHST po qo)-      pure $ cons p q ::: o-    (AnyOutInstr p, q ::: qo) -> do-      pure $ cons p q ::: qo-    (p ::: po, AnyOutInstr q) -> do-      pure $ cons p q ::: po-    (AnyOutInstr p, AnyOutInstr q) ->-      pure $ AnyOutInstr (cons p q)+  let cons1 opsT = mCons opsT (map (IllTypedOp . NonTypedInstr) mbf)+  preserving' (tcList mbt bti) cons1 $ \tInstr@(_ :/ pinstr) -> do+    let cons2 opsF = mCons [someInstrToOp tInstr] opsF+    preserving (tcList mbf bfi) cons2 $ \(_ :/ qinstr) -> do+      fmap (i :/) $ case (pinstr, qinstr) of+        (p ::: po, q ::: qo) -> do+          let instr = mCons mbt mbf+          Refl <- onTypeCheckInstrErr instr (SomeHST i) (Just If)+            $ eqHST po qo+          o <- onTypeCheckInstrAnnErr instr i (Just If) (convergeHST po qo)+          pure $ cons p q ::: o+        (AnyOutInstr p, q ::: qo) -> do+          pure $ cons p q ::: qo+        (p ::: po, AnyOutInstr q) -> do+          pure $ cons p q ::: po+        (AnyOutInstr p, AnyOutInstr q) ->+          pure $ AnyOutInstr (cons p q)  mapImpl   :: forall c rs .@@ -1129,26 +1254,27 @@     , WellTyped (MapOpInp c)     , Typeable (MapOpRes c)     )-  => Notes (MapOpInp c)+  => ([TypeCheckedOp] -> TypeCheckedInstr)+  -> Notes (MapOpInp c)   -> U.ExpandedInstr   -> [U.ExpandedOp]   -> HST (c ': rs)   -> (forall v' . (KnownT v') =>         Notes v' -> HST rs -> TypeCheckInstr (HST (MapOpRes c v' ': rs)))-  -> TypeCheckInstr (SomeInstr (c ': rs))-mapImpl vn instr mp i@(_ ::& rs) mkRes = do-  _ :/ subp <- lift $ typeCheckList mp ((vn, Dict, def) ::& rs)-  case subp of-    sub ::: subo ->-      case subo of-        (bn, _, _bvn) ::& rs' -> do-          Refl <- onTypeCheckInstrErr instr (SomeHST i) (Just Iteration)-            $ eqHST rs rs'-          x <- mkRes bn rs'-          pure $ i :/ MAP sub ::: x-        _ -> typeCheckInstrErr instr (SomeHST i) (Just Iteration)-    AnyOutInstr _ ->-      typeCheckInstrErr' instr (SomeHST i) (Just Iteration) CodeAlwaysFails+  -> TypeCheckInstrNoExcept (TypeCheckedSeq (c ': rs))+mapImpl cons vn instr mp i@(_ ::& rs) mkRes = do+  preserving (tcList mp ((vn, Dict, def) ::& rs)) cons $ \(_ :/ subp) ->+    case subp of+      sub ::: subo ->+        case subo of+          (bn, _, _bvn) ::& rs' -> do+            Refl <- onTypeCheckInstrErr instr (SomeHST i) (Just Iteration)+              $ eqHST rs rs'+            x <- mkRes bn rs'+            pure $ i :/ MAP sub ::: x+          _ -> typeCheckInstrErr instr (SomeHST i) (Just Iteration)+      AnyOutInstr _ ->+        typeCheckInstrErr' instr (SomeHST i) (Just Iteration) CodeAlwaysFails  iterImpl   :: forall c rs .@@ -1159,17 +1285,16 @@   -> U.ExpandedInstr   -> [U.ExpandedOp]   -> HST (c ': rs)-  -> TypeCheckInstr (SomeInstr (c ': rs))+  -> TypeCheckInstrNoExcept (TypeCheckedSeq (c ': rs)) iterImpl en instr mp i@((_, _, lvn) ::& rs) = do   let evn = deriveVN "elt" lvn-  _ :/ subp <--    case mp of-      [] -> typeCheckInstrErr' instr (SomeHST i) (Just Iteration) EmptyCode-      _ -> typeCheckImpl typeCheckInstr mp ((en, Dict, evn) ::& rs)-  case subp of+  let tcAction = case mp of+        [] -> workOnInstr instr+          (typeCheckInstrErr' instr (SomeHST i) (Just Iteration) EmptyCode)+        _ -> typeCheckImpl typeCheckInstr mp ((en, Dict, evn) ::& rs)+  preserving tcAction U.ITER $ \(_ :/ subp) -> case subp of     subI ::: o -> do-      Refl <- onTypeCheckInstrErr instr (SomeHST i) (Just Iteration)-        $ eqHST o rs+      Refl <- onTypeCheckInstrErr instr (SomeHST i) (Just Iteration) $ eqHST o rs       pure $ i :/ ITER subI ::: o     AnyOutInstr _ ->       typeCheckInstrErr' instr (SomeHST i) (Just Iteration) CodeAlwaysFails@@ -1179,29 +1304,31 @@     ( WellTyped it, WellTyped ot     , Typeable ts     )-  => U.ExpandedInstr+  => ([TypeCheckedOp] -> TypeCheckedInstr)+  -> U.ExpandedInstr   -> [U.ExpandedOp]   -> VarAnn   -> Notes it   -> Notes ot   -> HST ts-  -> TypeCheckInstr (SomeInstr ts)-lamImpl instr is vn ins ons i = do-  whenJust (getFirst $ foldMap hasSelf is) $ \selfInstr ->-    typeCheckInstrErr' instr (SomeHST i) (Just LambdaCode) $ InvalidInstruction selfInstr-  _ :/ lamI <- lift $ typeCheckList is ((ins, Dict, def) ::& SNil)-  let lamNotes onsr = NTLambda def ins onsr-  let lamSt onsr = (lamNotes onsr, Dict, vn) ::& i-  fmap (i :/) $ case lamI of-    lam ::: lo -> do-      case eqHST1 @ot lo of-        Right Refl -> do-            let (ons', _, _) ::& SNil = lo-            onsr <- onTypeCheckInstrAnnErr instr i (Just LambdaCode) (converge ons ons')-            pure (LAMBDA (VLam $ RfNormal lam) ::: lamSt onsr)-        Left m -> typeCheckInstrErr' instr (SomeHST i) (Just LambdaCode) m-    AnyOutInstr lam ->-      pure (LAMBDA (VLam $ RfAlwaysFails lam) ::: lamSt ons)+  -> TypeCheckInstrNoExcept (TypeCheckedSeq ts)+lamImpl cons instr is vn ins ons i =+  guarding_ instr+    (whenJust (getFirst $ foldMap hasSelf is) $ \selfInstr ->+      typeCheckInstrErr' instr (SomeHST i) (Just LambdaCode) $ InvalidInstruction selfInstr) $+    preserving (tcList is ((ins, Dict, def) ::& SNil)) cons $ \(_ :/ lamI) -> do+      let lamNotes onsr = NTLambda def ins onsr+      let lamSt onsr = (lamNotes onsr, Dict, vn) ::& i+      fmap (i :/) $ case lamI of+        lam ::: lo -> do+          case eqHST1 @ot lo of+            Right Refl -> do+                let (ons', _, _) ::& SNil = lo+                onsr <- onTypeCheckInstrAnnErr instr i (Just LambdaCode) (converge ons ons')+                pure (LAMBDA (VLam $ RfNormal lam) ::: lamSt onsr)+            Left m -> typeCheckInstrErr' instr (SomeHST i) (Just LambdaCode) m+        AnyOutInstr lam ->+          pure (LAMBDA (VLam $ RfAlwaysFails lam) ::: lamSt ons)   where     hasSelf :: U.ExpandedOp -> First U.ExpandedInstr     hasSelf = everything (<>)@@ -1218,27 +1345,37 @@  -- Helper data type we use to typecheck DIPN. data TCDipHelper inp where-  TCDipHelper ::+  TCDipHelperOk ::     forall (n :: Peano) inp out s s'.     (Typeable out, ConstraintDIPN n inp out s s') =>     Sing n -> Instr s s' -> HST out -> TCDipHelper inp+  TCDipHelperErr :: TCError -> [IllTypedInstr] -> TCDipHelper inp -typeCheckDipBody ::-     forall inp r. Typeable inp-  => U.ExpandedInstr+typeCheckDipBody+  :: Typeable inp+  => ([TypeCheckedOp] -> TypeCheckedInstr)+  -> U.ExpandedInstr   -> [U.ExpandedOp]   -> HST inp-  -> (forall out. Typeable out =>-                    Instr inp out -> HST out -> TypeCheckInstr r)-  -> TypeCheckInstr r-typeCheckDipBody mainInstr instructions inputHST callback = do-  _ :/ tp <- lift (typeCheckList instructions inputHST)-  case tp of-    AnyOutInstr _ ->-      -- This may seem like we throw error because of despair, but in fact,-      -- the reference implementation seems to behave exactly in this way --      -- if output stack of code block within @DIP@ occurs to be any, an-      -- error "FAILWITH must be at tail position" is raised.-      -- It is not allowed even in `DIP 0`.-      typeCheckInstrErr' mainInstr (SomeHST inputHST) (Just DipCode) CodeAlwaysFails-    subI ::: t -> callback subI t+  -> (TCError -> [IllTypedInstr] -> r)+  -> (forall out. Typeable out => Instr inp out -> HST out -> r)+  -> TypeCheckInstrNoExcept r+typeCheckDipBody cons mainInstr instructions inputHST onErr onOk = do+  listRes <- lift $ typeCheckListNoExcept instructions inputHST+  pos <- ask+  pure $ listRes & tcsEither+    (\tcOps err -> onErr err [SemiTypedInstr $ cons tcOps])+    (\someInstr@(_ :/ iAndOut) -> case iAndOut of+        AnyOutInstr _ ->+        -- This may seem like we throw error because of despair, but in fact,+        -- the reference implementation seems to behave exactly in this way -+        -- if output stack of code block within @DIP@ occurs to be any, an+        -- error "FAILWITH must be at tail position" is raised.+        -- It is not allowed even in `DIP 0`.+          let err = TCFailedOnInstr mainInstr+                                    (SomeHST inputHST)+                                    pos+                                    (Just DipCode)+                                    (Just CodeAlwaysFails)+          in onErr err [SemiTypedInstr $ cons [someInstrToOp someInstr]]+        subI ::: t -> onOk subI t)
src/Michelson/TypeCheck/TypeCheck.hs view
@@ -6,13 +6,24 @@   ( TcInstrHandler   , TcOriginatedContracts   , TcResult-  , TypeCheckEnv (..)+  , TypeCheckEnv(..)+  , TypeCheckOptions(..)   , TypeCheck+  , TypeCheckNoExcept   , runTypeCheck   , TypeCheckInstr+  , TypeCheckInstrNoExcept   , runTypeCheckIsolated   , runTypeCheckInstrIsolated-  , mapTCError+  , liftNoExcept+  , liftNoExcept'+  , throwingTCError+  , throwingTCError'+  , preserving+  , preserving'+  , guarding+  , guarding_+  , tcEither    , tcExtFramesL   , tcModeL@@ -22,15 +33,18 @@   , mkSomeParamTypeUnsafe   ) where -import Control.Monad.Except (withExceptT)-import Control.Monad.Reader (mapReaderT)-import Data.Default (def)++import Control.Monad.Except (throwError)+import Data.Default (Default(..)) import Data.Singletons (Sing) import Fmt (Buildable, build, pretty) import qualified Text.Show  import Michelson.ErrorPos (InstrCallStack) import Michelson.TypeCheck.Error (TCError(..), TCTypeError(..))+import Michelson.TypeCheck.TypeCheckedSeq+  (IllTypedInstr(..), TypeCheckedInstr, TypeCheckedOp(..), TypeCheckedSeq(..), someInstrToOp,+  tcsEither) import Michelson.TypeCheck.Types import qualified Michelson.Typed as T import qualified Michelson.Untyped as U@@ -38,9 +52,16 @@ import Util.Lens  type TypeCheck =-  ExceptT TCError-    (State TypeCheckEnv)+  (ReaderT TypeCheckOptions+    (ExceptT TCError+      (State TypeCheckEnv))) +-- | A non-throwing alternative for @TypeCheck@. Mainly meant to be used for+-- construction of a partially typed tree (see @TypeCheckedSeq@).+type TypeCheckNoExcept =+  (ReaderT TypeCheckOptions+    (State TypeCheckEnv))+ data SomeParamType = forall t. (T.ParameterScope t) =>   SomeParamType (Sing t) (T.ParamNotes t) @@ -96,10 +117,20 @@   , tcMode :: ~TypeCheckMode   } +data TypeCheckOptions = TypeCheckOptions+  { tcVerbose :: Bool -- ^ Whether to add stack type comments after every+                      -- instruction a la tezos-client.+  }++instance Default TypeCheckOptions where+  def = TypeCheckOptions{ tcVerbose = False }+ makeLensesWith postfixLFields ''TypeCheckEnv -runTypeCheck :: TypeCheckMode -> TypeCheck a -> Either TCError a-runTypeCheck mode = evaluatingState (TypeCheckEnv [] mode) . runExceptT+runTypeCheck :: TypeCheckMode -> TypeCheckOptions -> TypeCheck a -> Either TCError a+runTypeCheck mode options = evaluatingState (TypeCheckEnv [] mode)+                          . runExceptT+                          . usingReaderT options  -- | Run type checker as if it worked isolated from other world - -- no access to environment of the current contract is allowed.@@ -110,22 +141,108 @@ -- contract which is being typechecked (because there is no contract -- that we are typechecking). runTypeCheckIsolated :: TypeCheck a -> Either TCError a-runTypeCheckIsolated = runTypeCheck TypeCheckTest+runTypeCheckIsolated = runTypeCheck TypeCheckTest def  type TcResult inp = Either TCError (SomeInstr inp)  type TypeCheckInstr =-       ReaderT InstrCallStack TypeCheck+  ReaderT InstrCallStack TypeCheck +type TypeCheckInstrNoExcept =+  ReaderT InstrCallStack TypeCheckNoExcept+ -- | Similar to 'runTypeCheckIsolated', but for 'TypeCheckInstr.' runTypeCheckInstrIsolated :: TypeCheckInstr a -> Either TCError a-runTypeCheckInstrIsolated =-  runTypeCheckIsolated . flip runReaderT def+runTypeCheckInstrIsolated = runTypeCheckIsolated . flip runReaderT def --- | Run 'TypeCheckInstr' and modify thrown errors using given functions.-mapTCError :: (TCError -> TCError) -> TypeCheckInstr a -> TypeCheckInstr a-mapTCError f = mapReaderT (withExceptT f)+liftNoExcept :: TypeCheckInstrNoExcept a -> TypeCheckInstr a+liftNoExcept action = (pure action)+                 <**> (usingReaderT <$> ask)+                 <**> (usingReaderT <$> lift ask)+                 <**> (evaluatingState <$> get) +liftNoExcept' :: TypeCheckNoExcept a -> TypeCheck a+liftNoExcept' action = (pure action)+                  <**> (usingReaderT <$> ask)+                  <**> (evaluatingState <$> get)++throwingTCError+  :: TypeCheckInstrNoExcept (TypeCheckedSeq inp) -> TypeCheckInstr (SomeInstr inp)+throwingTCError action = liftNoExcept action+  >>= tcsEither (const throwError) (pure)++throwingTCError'+  :: TypeCheckNoExcept (TypeCheckedSeq inp) -> TypeCheck (SomeInstr inp)+throwingTCError' action = liftNoExcept' action+  >>= tcsEither (const throwError) (pure)++tcEither+  :: (TCError -> TypeCheckInstrNoExcept a) -- ^ Call this if the action throws+  -> (b -> TypeCheckInstrNoExcept a) -- ^ Call this if it doesn't+  -> TypeCheckInstr b -- ^ The action to perform+  -> TypeCheckInstrNoExcept a -- ^ A non-throwing action+tcEither onErr onOk action = do+  res <- (pure action)+    <**> (usingReaderT <$> ask)+    <**> (usingReaderT <$> lift ask)+    <**> (pure runExceptT)+    <**> (evaluatingState <$> get)+  either onErr onOk res++-- | Perform a throwing action on an acquired instruction. Preserve the acquired+-- result by embedding it into a type checking tree with a specified parent+-- instruction.+preserving+  :: TypeCheckInstrNoExcept (TypeCheckedSeq inp)+  -- ^ Acquiring computation+  -> ([TypeCheckedOp] -> TypeCheckedInstr)+  -- ^ The parent instruction constructor+  -> (SomeInstr inp -> TypeCheckInstr (SomeInstr inp'))+  -- ^ The throwing action+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp')+preserving acquire con action = preserving' acquire con+  (\instr -> action instr & tcEither+    (\err -> pure $ IllTypedSeq err [SemiTypedInstr $ con [someInstrToOp instr]])+    (pure . WellTypedSeq))++-- | Perform a non-throwing action on an acquired instruction. Preserve the+-- acquired result even if the action does not succeed. Embed the result into a+-- type checking tree with a specified parent instruction.+preserving'+  :: TypeCheckInstrNoExcept (TypeCheckedSeq inp)+  -- ^ Acquiring computation+  -> ([TypeCheckedOp] -> TypeCheckedInstr)+  -- ^ The parent instruction constructor+  -> (SomeInstr inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp'))+  -- ^ The action+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp')+preserving' acquire con action =+  acquire >>= tcsEither+    (\tcOps err -> pure $ IllTypedSeq err [SemiTypedInstr $ con tcOps])+    (action)++-- | Acquire a resource. If successfully, call a follow-up action on it,+-- otherwise embed the error into a type checking tree along with a specified+-- untyped instruction.+guarding+  :: U.ExpandedInstr -- ^ Untyped instruction+  -> TypeCheckInstr a -- ^ Acquiring computation+  -> (a -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)) -- ^ Follow-up action+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+guarding instr cond action = do+  cond & tcEither+    (\err -> pure $ IllTypedSeq err [NonTypedInstr $ U.PrimEx instr])+    (action)++-- | Same as @guarding@ but doesn't pass an acquired result to a follow-up+-- action.+guarding_+  :: U.ExpandedInstr+  -> TypeCheckInstr a+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+  -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)+guarding_ instr cond action = guarding instr cond (const action)+ -- pva701: it's really painful to add arguments to TcInstrHandler -- due to necessity to refactor @typeCheckInstr@. -- Also functions which are being called from @typeCheckInstr@ would@@ -135,4 +252,4 @@    = forall inp. (Typeable inp, HasCallStack)       => U.ExpandedInstr       -> HST inp-      -> TypeCheckInstr (SomeInstr inp)+      -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
+ src/Michelson/TypeCheck/TypeCheckedOp.hs view
@@ -0,0 +1,62 @@+-- SPDX-FileCopyrightText: 2020 Tocqueville Group+--+-- SPDX-License-Identifier: LicenseRef-MIT-TQ++-- This module provides data types for representing partially typed+-- instructions.+module Michelson.TypeCheck.TypeCheckedOp+  ( TypeCheckedInstr+  , TypeCheckedOp(..)+  , IllTypedInstr(..)+  , someInstrToOp+  ) where++import Data.Typeable (cast)++import Michelson.Printer.Util (RenderDoc(..), renderOpsListNoBraces)+import Michelson.TypeCheck.Types (HST(..), SomeInstr(..), SomeInstrOut(..))+import Michelson.Typed.Convert (instrToOps)+import Michelson.Typed.Instr (Instr)+import Michelson.Untyped.Instr (ExpandedOp, InstrAbstract(..))+import Util.TH (deriveGADTNFData)++-- | Represents a root of a partially typed operation tree.+type TypeCheckedInstr = InstrAbstract TypeCheckedOp++-- | Represents nodes of a partially typed operation tree.+data TypeCheckedOp where+  -- | Constructs well-typed node.+  WellTypedOp :: (Typeable inp, Typeable out) => Instr inp out -> TypeCheckedOp+  -- | Constructs ill-typed node which might in turn contain well-typed and+  -- non-typed operations.+  IllTypedOp :: IllTypedInstr -> TypeCheckedOp++instance Eq TypeCheckedOp where+  WellTypedOp i1 == WellTypedOp i2 = cast i1 == Just i2+  IllTypedOp i1 == IllTypedOp i2 = i1 == i2+  _ == _ = False++-- | Represents a non-well-typed operation+data IllTypedInstr+  = SemiTypedInstr TypeCheckedInstr -- ^ Constructs a partialy typed operation.+  | NonTypedInstr ExpandedOp  -- ^ Constructs a completely untyped operation.+  deriving stock (Eq, Generic)++deriving anyclass instance NFData TypeCheckedOp => NFData IllTypedInstr++instance RenderDoc TypeCheckedOp where+  renderDoc _ (WellTypedOp instr) = renderOpsListNoBraces False (instrToOps instr)+  renderDoc pn (IllTypedOp (SemiTypedInstr instr)) = renderDoc pn instr+  renderDoc pn (IllTypedOp (NonTypedInstr op)) = renderDoc pn op++-- | Makes a well-typed node out of `SomeInstr`+someInstrToOp :: SomeInstr inp -> TypeCheckedOp+someInstrToOp (hst :/ rest) = case hst of+  SNil -> go rest+  (::&){} -> go rest+  where+    go :: forall inp. Typeable inp => SomeInstrOut inp -> TypeCheckedOp+    go (i ::: _) = WellTypedOp i+    go (AnyOutInstr i) = WellTypedOp (i @'[])++$(deriveGADTNFData ''TypeCheckedOp)
+ src/Michelson/TypeCheck/TypeCheckedSeq.hs view
@@ -0,0 +1,51 @@+-- SPDX-FileCopyrightText: 2020 Tocqueville Group+--+-- SPDX-License-Identifier: LicenseRef-MIT-TQ++-- | This module provides a data type for representing a partially typed+-- sequence of instructions.+--+-- It is needed to represent the fact that there can only be one well-typed node+-- in a sequence and it is the first one. Also, it serves its role to remove+-- @TCError@ usage from @TypeCheckedOp@.+module Michelson.TypeCheck.TypeCheckedSeq+  ( TypeCheckedInstr+  , TypeCheckedOp(..)+  , IllTypedInstr(..)+  , TypeCheckedSeq(..)+  , tcsEither+  , seqToOps+  , someInstrToOp+  ) where++import Michelson.TypeCheck.Error (TCError)+import Michelson.TypeCheck.TypeCheckedOp+  (IllTypedInstr(..), TypeCheckedInstr, TypeCheckedOp(..), someInstrToOp)+import Michelson.TypeCheck.Types (SomeInstr(..))++-- | Represents a partiall typed sequence of instructions.+data TypeCheckedSeq inp+  -- | A fully well-typed sequence.+  = WellTypedSeq (SomeInstr inp)+  -- | A well-typed prefix followed by some error and semi-typed instructions.+  | MixedSeq (SomeInstr inp) TCError [IllTypedInstr]+  -- | There is no well-typed prefix, only an error and semi-typed instructions.+  | IllTypedSeq TCError [IllTypedInstr]++seqToOps :: TypeCheckedSeq inp -> [TypeCheckedOp]+seqToOps = \case+  WellTypedSeq instr -> [someInstrToOp instr]+  MixedSeq instr _ tail' -> someInstrToOp instr : map IllTypedOp tail'+  IllTypedSeq _ tail' -> map IllTypedOp tail'++-- | Case analysis for @TypeCheckedSeq@.+tcsEither+  :: ([TypeCheckedOp] -> TCError -> a)+     -- ^ On error, with all already typechecked operations+  -> (SomeInstr inp -> a) -- ^ On well-typed instruction+  -> TypeCheckedSeq inp -- ^ The sequence to dispatch on+  -> a+tcsEither onErr onInstr v = case v of+  WellTypedSeq instr -> onInstr instr+  MixedSeq _ err _ -> onErr (seqToOps v) err+  IllTypedSeq err _ -> onErr (seqToOps v) err
src/Michelson/TypeCheck/Types.hs view
@@ -18,13 +18,15 @@     , withWTPm     , unsafeWithWTP     , mapSomeContract+    , mapSomeInstr+    , mapSomeInstrOut     , noBoundVars     ) where  import Data.Constraint (Dict(..)) import qualified Data.Map.Lazy as Map import Data.Singletons (Sing, SingI(..), demote)-import Fmt (Buildable(..), Builder, (+|), (|+))+import Fmt (Buildable(..), Builder, (+|), (|+), pretty) import Prelude hiding (EQ, GT, LT) import qualified Text.Show @@ -164,6 +166,19 @@   (:/) :: HST inp -> SomeInstrOut inp -> SomeInstr inp infix 8 :/ +mapSomeInstrOut+  :: (forall out. Instr inp out -> Instr inp' out)+  -> SomeInstrOut inp+  -> SomeInstrOut inp'+mapSomeInstrOut f (i ::: out) = f i ::: out+mapSomeInstrOut f (AnyOutInstr i) = AnyOutInstr (f i)++mapSomeInstr+  :: (forall out. Instr inp out -> Instr inp out)+  -> SomeInstr inp+  -> SomeInstr inp+mapSomeInstr f (inp :/ instrAndOut) = inp :/ mapSomeInstrOut f instrAndOut+ instance Show (ExtInstr inp) => Show (SomeInstr inp) where   show (inp :/ out) = show inp <> " -> " <> show out @@ -204,6 +219,11 @@ -- | Error type for when a value is not well-typed. data NotWellTyped = NotWellTyped T +instance Buildable NotWellTyped where+  build (NotWellTyped t) =+    "Given type is not well typed because it has an non-comparable type in it: \+    \'" <> (build t) <> "', where a comparable type is required"+ fromEDict :: Either e (Dict a) -> (a => Either e (Dict b)) -> Either e (Dict b) fromEDict ma b = ma >>= (\Dict -> b) @@ -257,12 +277,10 @@ withWTPm :: forall t m a. (MonadFail m, SingI t) => (WellTyped t => m a) -> m a withWTPm a = case getWTP @t of   Right Dict -> a-  Left (NotWellTyped t) ->-    fail ("This type is not well typed because it has an non-comparable type in it: '" <> (show t) <>-      "', where a comparable type is required")+  Left e -> fail (pretty e)  -- | Similar to @withWTPm@ but is mean to be used within tests. unsafeWithWTP :: forall t a. SingI t => (WellTyped t => a) -> a unsafeWithWTP fn = case getWTP @t of   Right Dict -> fn-  Left (NotWellTyped t) -> error $ "Type is not well typed: " <> (show t)+  Left e -> error $ pretty e
src/Michelson/TypeCheck/Value.hs view
@@ -19,11 +19,11 @@ import Michelson.Text import Michelson.TypeCheck.Error (TCError(..), TCTypeError(..)) import Michelson.TypeCheck.Helpers-import Michelson.TypeCheck.TypeCheck (SomeParamType(..), TcInstrHandler, TcOriginatedContracts, TypeCheckInstr)+import Michelson.TypeCheck.TypeCheck+  (SomeParamType(..), TcInstrHandler, TcOriginatedContracts, TypeCheckInstr, throwingTCError) import Michelson.TypeCheck.Types import Michelson.Typed-  (EpAddress(..), KnownT, Notes(..), SingT(..), Value'(..),-  fromSingT, starNotes)+  (EpAddress(..), KnownT, Notes(..), SingT(..), Value'(..), fromSingT, starNotes) import qualified Michelson.Typed as T import qualified Michelson.Untyped as U import Tezos.Address (Address(..))@@ -168,7 +168,9 @@           U.ValueNil       -> pure []           U.ValueLambda mp -> pure $ toList mp           _ -> tcFailedOnValue v (demote @ty) "unexpected value" Nothing-        _ :/ instr <- withWTP @it uvalue $ typeCheckImpl tcDo mp ((starNotes @it, Dict, def) ::& SNil)+        _ :/ instr <-+          withWTP @it uvalue $ throwingTCError $+            typeCheckImpl tcDo mp ((starNotes @it, Dict, def) ::& SNil)         case instr of           lam ::: (lo :: HST lo) -> withWTP @ot uvalue $ do             case eqHST1 @ot lo of
src/Michelson/Typed/Annotation.hs view
@@ -49,7 +49,7 @@ -- -- Each constructor corresponds to exactly one constructor of 'T' -- and holds all type and field annotations that can be attributed to a--- Michelson type corrspoding to @t@.+-- Michelson type corresponding to @t@. data Notes t where   NTKey       :: TypeAnn -> Notes 'TKey   NTUnit      :: TypeAnn -> Notes 'TUnit
src/Michelson/Typed/Convert.hs view
@@ -5,20 +5,24 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}  module Michelson.Typed.Convert-  ( convertContractCode+  ( convertParamNotes+  , convertContractCode   , convertContract   , instrToOps   , untypeValue    -- Helper for generating documentation   , sampleValueFromUntype++  -- * Misc+  , flattenEntrypoints   ) where  import Data.Constraint (Dict(..)) import qualified Data.Map as Map import qualified Data.Set as Set import Data.Singletons (Sing, demote)-import Fmt (Buildable(..), pretty)+import Fmt (Buildable(..), fmt, listF, pretty)  import Michelson.Text import Michelson.Typed.Aliases@@ -31,12 +35,15 @@ import Michelson.Typed.T (T(..)) import Michelson.Typed.Value import qualified Michelson.Untyped as U-import Tezos.Core-  (mformatChainId, parseChainId, timestampFromSeconds, unMutez, unsafeMkMutez)+import Tezos.Core (mformatChainId, parseChainId, timestampFromSeconds, unMutez, unsafeMkMutez) import Tezos.Crypto import Util.Peano import Util.Typeable +convertParamNotes :: SingI cp => ParamNotes cp -> U.ParameterType+convertParamNotes (ParamNotes notes rootAnn) =+  U.ParameterType (mkUType notes) rootAnn+ convertContractCode   :: forall param store . (SingI param, SingI store)   => ContractCode param store -> U.Contract@@ -53,8 +60,7 @@   => Contract param store -> U.Contract convertContract fc =   let c = convertContractCode (cCode fc)-  in c { U.contractParameter = U.ParameterType (mkUType (pnNotes $ cParamNotes fc))-         (pnRootAnn (cParamNotes fc))+  in c { U.contractParameter = convertParamNotes (cParamNotes fc)        , U.contractStorage = mkUType (cStoreNotes fc)        , U.entriesOrder = cEntriesOrder fc        }@@ -318,7 +324,7 @@             U.SLICE _ -> U.SLICE va             U.ISNAT _ -> U.ISNAT va             U.ADD _ -> U.ADD va-            U.SUB _ -> U.MUL va+            U.SUB _ -> U.SUB va             U.MUL _ -> U.MUL va             U.EDIV _ -> U.EDIV va             U.ABS _ -> U.ABS va@@ -332,9 +338,10 @@             U.COMPARE _ -> U.COMPARE va             U.EQ _ -> U.EQ va             U.NEQ _ -> U.NEQ va-            U.LT _ -> U.GT va+            U.LT _ -> U.LT va             U.GT _ -> U.GT va-            U.LE _ -> U.GE va+            U.LE _ -> U.LE va+            U.GE _ -> U.GE va             U.INT _ -> U.INT va             U.SELF _ fa -> U.SELF va fa             U.CONTRACT _ fa t -> U.CONTRACT va fa t@@ -346,7 +353,8 @@             U.AMOUNT _ -> U.AMOUNT va             U.BALANCE _ -> U.BALANCE va             U.CHECK_SIGNATURE _ -> U.CHECK_SIGNATURE va-            U.SHA256 _ -> U.SHA512 va+            U.SHA256 _ -> U.SHA256 va+            U.SHA512 _ -> U.SHA512 va             U.BLAKE2B _ -> U.BLAKE2B va             U.HASH_KEY _ -> U.HASH_KEY va             U.SOURCE _ -> U.SOURCE va@@ -501,6 +509,8 @@       StatementStarts name -> one $ U.UCOMMENT $ "Statement starts: " <> name       StatementEnds name -> one $ U.UCOMMENT $ "Statement ends: " <> name       JustComment com -> one $ U.UCOMMENT com+      StackTypeComment (Just stack) -> one $ U.UCOMMENT $ pretty (listF stack)+      StackTypeComment Nothing -> one $ U.UCOMMENT $ fmt "any stack type"  -- It's an orphan instance, but it's better than checking all cases manually. -- We can also move this convertion to the place where `Instr` is defined,@@ -604,3 +614,12 @@       sampleSignature = fromRight (error "impossible") $ parseSignature         "edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vb"       sampleChainId = fromRight (error "impossible") $ parseChainId "NetXUdfLh6Gm88t"++-- Misc+----------------------------------------------------------------------------++-- | Flatten a provided list of notes to a map of its entrypoints and its+-- corresponding utype. Please refer to 'mkEntrypointsMap' in regards to how+-- duplicate entrypoints are handled.+flattenEntrypoints :: SingI t => ParamNotes t -> Map EpName U.Type+flattenEntrypoints = U.mkEntrypointsMap . convertParamNotes
src/Michelson/Typed/Entrypoints.hs view
@@ -33,7 +33,6 @@   , mkEntrypointCall    , tyImplicitAccountParam-  , flattenEntrypoints      -- * Re-exports   , EpName (..)@@ -51,15 +50,12 @@ import qualified Data.List.NonEmpty as NE import qualified Data.Text as T import Fmt (Buildable(..), hexF, pretty, (+|), (|+))-import Test.QuickCheck (Arbitrary(..))  import Michelson.Text import Michelson.Typed.Annotation-import Michelson.Typed.Extract import Michelson.Typed.Scope import Michelson.Typed.Sing import Michelson.Typed.T-import qualified Michelson.Untyped as U import Michelson.Untyped.Annotation import Michelson.Untyped.Entrypoints import Tezos.Address@@ -144,9 +140,6 @@ unsafeParseEpAddress :: HasCallStack => Text -> EpAddress unsafeParseEpAddress = either (error . pretty) id . parseEpAddress -instance Arbitrary FieldAnn => Arbitrary EpAddress where-  arbitrary = EpAddress <$> arbitrary <*> arbitrary- -- | Parses byte representation of entrypoint address. -- -- For every address@@ -241,7 +234,7 @@         = mapMaybe (safeHead . tail)         . NE.group         . sort-        $ maybe allEps (: allEps) (epNameFromParamAnn $ convAnn ra)+        $ maybe allEps (: allEps) (epNameFromParamAnn ra)    whenJust (nonEmpty duplicatedEps) $ \dups ->     throwError $ ParamEpDuplicatedNames dups@@ -466,7 +459,7 @@ mkEntrypointCall epName (ParamNotes paramNotes root) =   asum   [ do-      epName' <- epNameFromParamAnn $ convAnn root+      epName' <- epNameFromParamAnn root       guard (epName == epName')       return $ MkEntrypointCallRes         paramNotes@@ -492,12 +485,3 @@ -- | "Parameter" type of implicit account. tyImplicitAccountParam :: ParamNotes 'TUnit tyImplicitAccountParam = ParamNotesUnsafe starNotes noAnn---- Misc--------------------------------------------------------------------------------- | Flatten a provided list of notes to a map of its entrypoints and its--- corresponding utype. Please refer to 'mkEntrypointsMap' in regards to how--- duplicate entrypoints are handled.-flattenEntrypoints :: SingI t => ParamNotes t -> Map EpName U.Type-flattenEntrypoints (pnNotes -> notes) = mkEntrypointsMap (mkUType notes)
src/Michelson/Typed/Haskell/Value.hs view
@@ -47,7 +47,6 @@ import GHC.Generics ((:*:)(..), (:+:)(..)) import qualified GHC.Generics as G import Named (NamedF(..))-import Test.QuickCheck (Arbitrary(..))  import Michelson.Text import Michelson.Typed.Aliases@@ -270,12 +269,6 @@   toVal = VBigMap . Map.mapKeys toVal . Map.map toVal . unBigMap   fromVal (VBigMap x) = BigMap $ Map.map fromVal $ Map.mapKeys fromVal x -instance-  ( WellTypedToT k, WellTypedToT v, Comparable (ToT k), Arbitrary k-  , Arbitrary v, Ord k-  ) => Arbitrary (BigMap k v) where-  arbitrary = BigMap <$> arbitrary- -- Generic magic ---------------------------------------------------------------------------- @@ -378,22 +371,34 @@ -- illegal as per Michelson typing rule. Using this class, we inductively -- enforce that a type and all types it contains are well typed as per -- Michelson's rules.-class KnownT t => WellTyped (t :: T) where+class (KnownT t, WellTypedSuperC t) => WellTyped (t :: T) where+  -- | Constraints required for instance of a given type.+  type WellTypedSuperC t :: Constraint+  type WellTypedSuperC t = ()  instance WellTyped 'TKey where instance WellTyped 'TUnit where instance WellTyped 'TSignature where instance WellTyped 'TChainId where-instance (WellTyped t) => WellTyped ('TOption t) where-instance (WellTyped t) => WellTyped ('TList t) where+instance WellTyped t => WellTyped ('TOption t) where+  type WellTypedSuperC ('TOption t) = WellTyped t+instance WellTyped t => WellTyped ('TList t) where+  type WellTypedSuperC ('TList t) = WellTyped t instance (Comparable t, WellTyped t) => WellTyped ('TSet t) where+  type WellTypedSuperC ('TSet t) = (Comparable t, WellTyped t) instance WellTyped 'TOperation where-instance (WellTyped t) => WellTyped ('TContract t) where-instance (WellTyped t1, WellTyped t2) => WellTyped ('TPair t1 t2)-instance (WellTyped t1, WellTyped t2) => WellTyped ('TOr t1 t2)-instance (WellTyped t1, WellTyped t2) => WellTyped ('TLambda t1 t2)-instance (Comparable k, WellTyped k, WellTyped v) => WellTyped ('TMap k v)-instance (Comparable k, WellTyped k, WellTyped v) => WellTyped ('TBigMap k v)+instance WellTyped t => WellTyped ('TContract t) where+  type WellTypedSuperC ('TContract t) = WellTyped t+instance (WellTyped t1, WellTyped t2) => WellTyped ('TPair t1 t2) where+  type WellTypedSuperC ('TPair t1 t2) = (WellTyped t1, WellTyped t2)+instance (WellTyped t1, WellTyped t2) => WellTyped ('TOr t1 t2) where+  type WellTypedSuperC ('TOr t1 t2) = (WellTyped t1, WellTyped t2)+instance (WellTyped t1, WellTyped t2) => WellTyped ('TLambda t1 t2) where+  type WellTypedSuperC ('TLambda t1 t2) = (WellTyped t1, WellTyped t2)+instance (Comparable k, WellTyped k, WellTyped v) => WellTyped ('TMap k v) where+  type WellTypedSuperC ('TMap k v) = (Comparable k, WellTyped k, WellTyped v)+instance (Comparable k, WellTyped k, WellTyped v) => WellTyped ('TBigMap k v) where+  type WellTypedSuperC ('TBigMap k v) = (Comparable k, WellTyped k, WellTyped v) instance WellTyped 'TInt instance WellTyped 'TNat instance WellTyped 'TString
src/Michelson/Typed/Instr.hs view
@@ -47,7 +47,8 @@ import Michelson.Typed.Sing (KnownT) import Michelson.Typed.T (T(..)) import Michelson.Typed.Value (Comparable, ContractInp, ContractOut, Value'(..))-import Michelson.Untyped (Annotation(..), EntriesOrder(..), FieldAnn, TypeAnn, VarAnn, entriesOrderToInt)+import Michelson.Untyped+  (Annotation(..), EntriesOrder(..), FieldAnn, TypeAnn, VarAnn, entriesOrderToInt) import Util.Peano import Util.TH import Util.Type (type (++), KnownList)@@ -444,6 +445,7 @@  | StatementStarts Text  | StatementEnds Text  | JustComment Text+ | StackTypeComment (Maybe [T]) -- ^ 'Nothing' for any stack type  deriving stock (Show, Generic)  instance NFData CommentType
src/Michelson/Typed/Polymorphic.hs view
@@ -15,6 +15,8 @@   , UpdOp (..)   , SliceOp (..)   , ConcatOp (..)+  , divMich+  , modMich   ) where  import qualified Data.ByteString as B@@ -201,7 +203,7 @@     if j == 0       then VOption $ Nothing       else VOption $ Just $-        VPair (VInt (div i j), VNat $ fromInteger (abs $ mod i j))+        VPair (VInt (divMich i j), VNat $ fromInteger $ modMich i j) instance EDivOp 'TInt 'TNat where   type EDivOpRes 'TInt 'TNat = 'TInt   type EModOpRes 'TInt 'TNat = 'TNat@@ -211,7 +213,7 @@     if j == 0       then VOption $ Nothing       else VOption $ Just $-        VPair (VInt (div i (toInteger j)), VNat $ (abs $ mod (fromInteger i) j))+        VPair (VInt (divMich i (toInteger j)), VNat $ fromInteger $ modMich i (toInteger j)) instance EDivOp 'TNat 'TInt where   type EDivOpRes 'TNat 'TInt = 'TInt   type EModOpRes 'TNat 'TInt = 'TNat@@ -221,7 +223,7 @@     if j == 0       then VOption $ Nothing       else VOption $ Just $-        VPair (VInt (div (toInteger i) j), VNat $ (abs $ mod i (fromInteger j)))+        VPair (VInt (divMich (toInteger i) j), VNat $ fromInteger $ modMich (toInteger i) j) instance EDivOp 'TNat 'TNat where   type EDivOpRes 'TNat 'TNat = 'TNat   type EModOpRes 'TNat 'TNat = 'TNat@@ -231,7 +233,7 @@     if j == 0       then VOption $ Nothing       else VOption $ Just $-        VPair (VNat (div i j), VNat $ (mod i j))+        VPair (VNat (divMich i j), VNat $ (modMich i j)) instance EDivOp 'TMutez 'TMutez where   type EDivOpRes 'TMutez 'TMutez = 'TNat   type EModOpRes 'TMutez 'TMutez = 'TMutez@@ -252,3 +254,21 @@     i `divModMutezInt` j <&> \case       (quotient, remainder) ->         VPair (VMutez quotient, VMutez remainder)++-- | Computing 'div' function in Michelson style.+-- When divisor is negative, Haskell gives x as integer part,+-- while Michelson gives x+1.+divMich :: Integral a => a -> a -> a+divMich divisible divisor = divisible `div` divisor + extra+  where+    extra =+      if divisor > 0+      then 0+      else 1++-- | Computing 'mod' function in Michelson style.+-- When divisor is negative, Haskell gives a negative modulo,+-- while there is a positive modulo in Michelson.+modMich :: Integral a => a -> a -> a+modMich divisible divisor = divisible - divisor * intPart+  where intPart = divMich divisible divisor
src/Michelson/Typed/Value.hs view
@@ -37,17 +37,17 @@   , eqValueExt   ) where -import GHC.TypeLits (ErrorMessage(..), TypeError)-import Data.Singletons (SingI (..), Sing)-import Data.Constraint (Dict (..), (\\))-import Data.Type.Bool (type (&&))-import Fmt (Buildable(build), (+|), (|+), Builder)+import Data.Constraint (Dict(..), (\\)) import qualified Data.Kind as Kind+import Data.Singletons (Sing, SingI(..))+import Data.Type.Bool (type (&&))+import Fmt (Buildable(build), Builder, (+|), (|+))+import GHC.TypeLits (ErrorMessage(..), TypeError)  import Michelson.Text (MText) import Michelson.Typed.Entrypoints-import Michelson.Typed.Sing import Michelson.Typed.Scope (BadTypeForScope(..), CheckScope(..), ParameterScope, StorageScope)+import Michelson.Typed.Sing import Michelson.Typed.T (T(..)) import Tezos.Address (Address) import Tezos.Core (ChainId, Mutez, Timestamp)
src/Michelson/Untyped/Annotation.hs view
@@ -171,17 +171,13 @@ data VarTag data SomeTag -data RootTag- type TypeAnn = Annotation TypeTag type FieldAnn = Annotation FieldTag type VarAnn = Annotation VarTag type SomeAnn = Annotation SomeTag --- | Root annotation was added in the Babylon, it looks the same as--- field annotation, but has slightly different semantic and can be used--- only in parameter 'ParameterType'.-type RootAnn = Annotation RootTag+-- | Field annotation for the entire parameter.+type RootAnn = Annotation FieldTag  instance KnownAnnTag FieldTag where   annPrefix = "%"@@ -189,8 +185,6 @@   annPrefix = "@" instance KnownAnnTag TypeTag where   annPrefix = ":"-instance KnownAnnTag RootTag where-  annPrefix = "%"  instance KnownAnnTag tag => RenderDoc (Annotation tag) where   renderDoc _ = renderAnn
src/Michelson/Untyped/Entrypoints.hs view
@@ -20,7 +20,6 @@ import Data.Aeson.TH (deriveJSON) import qualified Data.Map as Map import Fmt (Buildable(..), pretty, (+|), (|+))-import Test.QuickCheck (Arbitrary(..), suchThatMap)  import Michelson.Untyped.Annotation import Michelson.Untyped.Type@@ -153,30 +152,28 @@ unsafeBuildEpName :: HasCallStack => Text -> EpName unsafeBuildEpName = either (error . pretty) id . buildEpName -instance Arbitrary FieldAnn => Arbitrary EpName where-  arbitrary = arbitrary `suchThatMap` (rightToMaybe . epNameFromRefAnn)- instance HasCLReader EpName where   getReader = eitherReader (buildEpName . toText)   getMetavar = "ENTRYPOINT" --- | Given an untyped type, extract a map that maps entrypoint names to the--- their parameter types. If there are duplicate entrypoints in the given Type--- then the duplicate entrypoints at a deeper nesting level will get+-- | Given an untyped parameter type, extract a map that maps entrypoint names+-- to the their parameter types. If there are duplicate entrypoints in the+-- given Type then the duplicate entrypoints at a deeper nesting level will get -- overwritten with the ones that are on top.-mkEntrypointsMap :: Type -> Map EpName Type-mkEntrypointsMap (Type t _) = case t of-  -- We are only interested in `Or` branches to extract entrypoint-  -- annotations.-  TOr f1 f2 t1 t2 -> extractSubmap f1 t1 <> extractSubmap f2 t2-  _ -> mempty+mkEntrypointsMap :: ParameterType -> Map EpName Type+mkEntrypointsMap (ParameterType ty rootAnn) = mkEntrypointsMapRec rootAnn ty++-- | Version of 'mkEntrypointMaps' for plain untyped type.+mkEntrypointsMapRec :: FieldAnn -> Type -> Map EpName Type+mkEntrypointsMapRec curRootAnn ty =+  accountRoot curRootAnn <> accountTree ty   where-    extractSubmap :: FieldAnn -> Type -> Map EpName Type-    extractSubmap f1 t1 = let-      -- If the field annotation is not empty then merge this field-      -- annotation/type pair with the entrypoint map of inner type. Else-      -- just fetch entrypoint map of inner type.-      innerMap = mkEntrypointsMap t1-      in case epNameFromParamAnn f1 of-        Just epName -> Map.singleton epName t1 <> innerMap-        Nothing -> innerMap+    accountRoot rootAnn = Map.fromList $ do+      Just rootEp <- pure $ epNameFromParamAnn rootAnn+      return (rootEp, ty)++    accountTree (Type t _) = case t of+      -- We are only interested in `Or` branches to extract entrypoint+      -- annotations.+      TOr f1 f2 t1 t2 -> mkEntrypointsMapRec f1 t1 <> mkEntrypointsMapRec f2 t2+      _ -> mempty
src/Michelson/Untyped/Type.hs view
@@ -46,8 +46,7 @@   (Prettier(..), RenderContext, RenderDoc(..), addParens, buildRenderDoc, doesntNeedParens,   needsParens, wrapInParens) import Michelson.Untyped.Annotation-  (AnnotationSet, FieldAnn, RootAnn, TypeAnn, convAnn, emptyAnnSet, fullAnnSet, noAnn,-  singleAnnSet)+  (AnnotationSet, FieldAnn, RootAnn, TypeAnn, emptyAnnSet, fullAnnSet, noAnn, singleAnnSet) import Util.Aeson  -- Annotated type@@ -79,11 +78,11 @@ instance RenderDoc (Prettier ParameterType) where   renderDoc pn (Prettier w) = case w of     ParameterType (Type t ta) ra ->-      renderType t False pn (fullAnnSet [ta] [convAnn ra] [])+      renderType t False pn (fullAnnSet [ta] [ra] [])  instance RenderDoc ParameterType where   renderDoc pn (ParameterType (Type t ta) ra) =-    renderType t True pn (fullAnnSet [ta] [convAnn ra] [])+    renderType t True pn (fullAnnSet [ta] [ra] [])  -- Ordering between different kinds of annotations is not significant, -- but ordering among annotations of the same kind is. Annotations
src/Morley/Micheline/Class.hs view
@@ -22,7 +22,7 @@ import Michelson.Typed.Instr (mapEntriesOrdered) import Michelson.Typed.Scope (UnpackedValScope) import qualified Michelson.Untyped as Untyped-import Michelson.Untyped.Annotation (RootAnn, convAnn, noAnn)+import Michelson.Untyped.Annotation (RootAnn, noAnn) import Michelson.Untyped.Instr (ExpandedOp) import Morley.Micheline.Binary (decodeExpression, encodeExpression) import Morley.Micheline.Expression@@ -72,8 +72,7 @@       addRootAnnToExpression rootAnn expr = case expr of         ExpressionPrim p           | rootAnn /= noAnn -> ExpressionPrim p-            { mpaAnnots = mpaAnnots p |>-             (AnnotationField $ convAnn rootAnn)+            { mpaAnnots = mpaAnnots p |> AnnotationField rootAnn             }           | otherwise -> expr         -- Currently this error can't happen because parameter type
src/Morley/Micheline/Json.hs view
@@ -9,6 +9,7 @@   ( StringEncode (..)   , TezosBigNum   , TezosInt64+  , parseMutezJson   ) where  import Data.Aeson (FromJSON, ToJSON, parseJSON, toEncoding, toJSON)@@ -19,6 +20,8 @@ import Fmt (Buildable(..)) import qualified Text.Show as T +import Tezos.Core (Mutez, mkMutez')+ parseAsString :: forall a. (Read a, Typeable a) => Aeson.Value -> Aeson.Parser a parseAsString = Aeson.withText (T.show $ typeRep (Proxy :: Proxy a)) $ \txt ->   maybe (fail "Failed to parse string") pure $ readMaybe (toString txt)@@ -50,3 +53,7 @@ instance ToJSON TezosInt64 where   toJSON (StringEncode x) = Aeson.String $ show x   toEncoding (StringEncode x) = AE.int64Text x++parseMutezJson :: TezosInt64 -> Aeson.Parser Mutez+parseMutezJson (StringEncode i) =+  either (fail . toString) pure $ mkMutez' i
src/Tezos/Address.hs view
@@ -38,7 +38,6 @@ import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import Fmt (Buildable(build), hexF, pretty)-import Test.QuickCheck (Arbitrary(..), oneof, vector)  import Michelson.Text import Tezos.Crypto@@ -343,13 +342,3 @@   fromJSONKey =     AesonTypes.FromJSONKeyTextParser       (either (fail . pretty) pure . parseAddress)--------------------------------------------------------------------------------- Arbitrary-------------------------------------------------------------------------------instance Arbitrary Address where-  arbitrary = oneof [genKeyAddress, genContractAddress]-    where-      genKeyAddress = KeyAddress <$> arbitrary-      genContractAddress = ContractAddress . ContractHash . BS.pack <$> vector 20
src/Tezos/Core.hs view
@@ -9,6 +9,7 @@     -- * Mutez     Mutez (unMutez)   , mkMutez+  , mkMutez'   , unsafeMkMutez   , toMutez   , addMutez@@ -48,7 +49,6 @@ import Data.Aeson (FromJSON(..), ToJSON(..)) import qualified Data.Aeson as Aeson import Data.Aeson.TH (deriveJSON)-import qualified Data.ByteString as BS import Data.Data (Data(..)) import qualified Data.Text as T import Data.Time.Clock (UTCTime)@@ -60,12 +60,12 @@ import qualified Language.Haskell.TH.Quote as TH import Language.Haskell.TH.Syntax (liftData) import qualified Options.Applicative as Opt-import Test.QuickCheck (Arbitrary(..), vector)  import Michelson.Text import Tezos.Crypto import Util.Aeson import Util.CLI+import Util.Num  ---------------------------------------------------------------------------- -- Mutez@@ -99,6 +99,13 @@   | otherwise = Nothing {-# INLINE mkMutez #-} +-- | Version of 'mkMutez' that accepts a number of any type.+mkMutez' :: Integral i => i -> Either Text Mutez+mkMutez' i = do+  w :: Word64 <- fromIntegralChecked i+  mkMutez w+    & maybeToRight "Mutez overflow"+ -- | Partial function for 'Mutez' creation, it's pre-condition is that -- the argument must not exceed the maximal 'Mutez' value. unsafeMkMutez :: HasCallStack => Word64 -> Mutez@@ -321,6 +328,9 @@       ParseChainIdWrongSize s ->         "Wrong size for a chain id: " <> build s +instance Exception ParseChainIdError where+  displayException = pretty+ parseChainId :: Text -> Either ParseChainIdError ChainId parseChainId text =   case decodeBase58CheckWithPrefix chainIdPrefix text of@@ -339,9 +349,6 @@ -- Corresponds to "Net" part. chainIdPrefix :: ByteString chainIdPrefix = "\87\82\0"--instance Arbitrary ChainId where-  arbitrary = ChainIdUnsafe . BS.pack <$> (vector 4)  ---------------------------------------------------------------------------- -- JSON
src/Tezos/Crypto.hs view
@@ -93,7 +93,6 @@ import qualified Data.ByteString.Lazy as LBS import qualified Data.Text as T import Fmt (Buildable, build, hexF, pretty)-import Test.QuickCheck (Arbitrary(..), elements, oneof)  import Michelson.Text import qualified Tezos.Crypto.Ed25519 as Ed25519@@ -101,8 +100,8 @@ import qualified Tezos.Crypto.P256 as P256 import qualified Tezos.Crypto.Secp256k1 as Secp256k1 import Tezos.Crypto.Util-import Util.CLI import Util.Binary+import Util.CLI  ---------------------------------------------------------------------------- -- Types, instances, conversions@@ -121,9 +120,6 @@  instance NFData PublicKey -instance Arbitrary PublicKey where-  arbitrary = toPublic <$> arbitrary- -- | Secret cryptographic key used by Tezos. -- Constructors correspond to 'PublicKey' constructors. data SecretKey@@ -141,7 +137,6 @@   getReader = eitherReader (first pretty . parseSecretKey . toText)   getMetavar = "SECRET_KEY" - -- | Deterministicaly generate a secret key from seed. -- Type of the key depends on seed length. detSecretKey :: HasCallStack => ByteString -> SecretKey@@ -151,13 +146,6 @@   2 -> SecretKeyP256 . P256.detSecretKey   _ -> error "detSecretKey: unexpected happened" -instance Arbitrary SecretKey where-  arbitrary = oneof-    [ SecretKeyEd25519 <$> arbitrary-    , SecretKeySecp256k1 <$> arbitrary-    , SecretKeyP256 <$> arbitrary-    ]- -- | Create a public key from a secret key. toPublic :: SecretKey -> PublicKey toPublic = \case@@ -215,14 +203,6 @@     (SignatureP256 s1, SignatureP256 s2) -> s1 == s2     (SignatureP256 {}, _) -> False -instance Arbitrary Signature where-  arbitrary = oneof-    [ SignatureEd25519 <$> arbitrary-    , SignatureSecp256k1 <$> arbitrary-    , SignatureP256 <$> arbitrary-    , SignatureGeneric . BS.replicate signatureLengthBytes <$> arbitrary-    ]- ---------------------------------------------------------------------------- -- Signature ----------------------------------------------------------------------------@@ -427,9 +407,6 @@   | KeyHashP256   deriving stock (Show, Eq, Ord, Bounded, Enum, Generic) -instance Arbitrary KeyHashTag where-  arbitrary = elements [minBound .. ]- instance NFData KeyHashTag  -- | Blake2b_160 hash of a public key.@@ -446,9 +423,6 @@ -- or anything). keyHashLengthBytes :: Integral n => n keyHashLengthBytes = 20--instance Arbitrary KeyHash where-  arbitrary = hashKey <$> arbitrary  -- | Compute the b58check of a public key hash. hashKey :: PublicKey -> KeyHash
src/Tezos/Crypto/Ed25519.hs view
@@ -38,9 +38,7 @@ import Crypto.Error (onCryptoFailure) import qualified Crypto.PubKey.Ed25519 as Ed25519 import Data.ByteArray (ByteArray, ByteArrayAccess, convert)-import qualified Data.ByteString as BS import Fmt (Buildable, build)-import Test.QuickCheck (Arbitrary(..), vector)  import Michelson.Text import Tezos.Crypto.Hash@@ -55,9 +53,6 @@   { unPublicKey :: Ed25519.PublicKey   } deriving stock (Show, Eq, Generic) -instance Arbitrary PublicKey where-  arbitrary = toPublic <$> arbitrary- instance NFData PublicKey  -- | ED25519 secret cryptographic key.@@ -71,9 +66,6 @@ detSecretKey :: ByteString -> SecretKey detSecretKey seed = SecretKey $ deterministic seed Ed25519.generateSecretKey -instance Arbitrary SecretKey where-  arbitrary = detSecretKey . BS.pack <$> vector 32- -- | Create a public key from a secret key. toPublic :: SecretKey -> PublicKey toPublic = PublicKey . Ed25519.toPublic . unSecretKey@@ -82,9 +74,6 @@ newtype Signature = Signature   { unSignature :: Ed25519.Signature   } deriving stock (Show, Eq, Generic)--instance Arbitrary Signature where-  arbitrary = sign <$> arbitrary <*> (encodeUtf8 @String <$> arbitrary)  instance NFData Signature 
src/Tezos/Crypto/P256.hs view
@@ -40,11 +40,9 @@ import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import qualified Crypto.PubKey.ECC.Generate as ECC.Generate import Crypto.PubKey.ECC.Types (Curve(..), CurveName(..), getCurveByName)-import Crypto.Random (MonadRandom, drgNewSeed, seedFromInteger, withDRG)+import Crypto.Random (MonadRandom) import Data.ByteArray (ByteArray, ByteArrayAccess)-import qualified Data.ByteString as BS import Fmt (Buildable, build)-import Test.QuickCheck (Arbitrary(..), vector)  import Michelson.Text import Tezos.Crypto.Util@@ -61,9 +59,6 @@   { unPublicKey :: ECDSA.PublicKey   } deriving stock (Eq, Show, Generic) -instance Arbitrary PublicKey where-  arbitrary = toPublic <$> arbitrary- instance NFData PublicKey where   rnf (PublicKey (ECDSA.PublicKey cu q))     = rnfCurve cu `seq` rnf q@@ -87,9 +82,6 @@   return $     ECDSA.KeyPair curve (ECDSA.public_q publicKey) (ECDSA.private_d privateKey) -instance Arbitrary SecretKey where-  arbitrary = detSecretKey . BS.pack <$> vector 32- -- | Create a public key from a secret key. toPublic :: SecretKey -> PublicKey toPublic =@@ -100,14 +92,6 @@ newtype Signature = Signature   { unSignature :: ECDSA.Signature   } deriving stock (Show, Eq, Generic)--instance Arbitrary Signature where-  arbitrary = do-    seed <- drgNewSeed . seedFromInteger <$> arbitrary-    byteToSign <- arbitrary-    return $ fst $ withDRG seed $ do-      sk <- detSecretKeyDo-      sign sk (one byteToSign)  instance NFData Signature where   rnf (Signature (ECDSA.Signature a b)) = rnf a `seq` rnf b
src/Tezos/Crypto/Secp256k1.hs view
@@ -40,11 +40,9 @@ import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import qualified Crypto.PubKey.ECC.Generate as ECC.Generate import Crypto.PubKey.ECC.Types (Curve(..), CurveName(..), getCurveByName)-import Crypto.Random (MonadRandom, drgNewSeed, seedFromInteger, withDRG)+import Crypto.Random (MonadRandom) import Data.ByteArray (ByteArray, ByteArrayAccess)-import qualified Data.ByteString as BS import Fmt (Buildable, build)-import Test.QuickCheck (Arbitrary(..), vector)  import Michelson.Text import Tezos.Crypto.Util@@ -61,9 +59,6 @@   { unPublicKey :: ECDSA.PublicKey   } deriving stock (Eq, Show, Generic) -instance Arbitrary PublicKey where-  arbitrary = toPublic <$> arbitrary- instance NFData PublicKey where   rnf (PublicKey (ECDSA.PublicKey cu q))     = rnfCurve cu `seq` rnf q@@ -87,9 +82,6 @@   return $     ECDSA.KeyPair curve (ECDSA.public_q publicKey) (ECDSA.private_d privateKey) -instance Arbitrary SecretKey where-  arbitrary = detSecretKey . BS.pack <$> vector 32- -- | Create a public key from a secret key. toPublic :: SecretKey -> PublicKey toPublic =@@ -100,14 +92,6 @@ newtype Signature = Signature   { unSignature :: ECDSA.Signature   } deriving stock (Show, Eq, Generic)--instance Arbitrary Signature where-  arbitrary = do-    seed <- drgNewSeed . seedFromInteger <$> arbitrary-    byteToSign <- arbitrary-    return $ fst $ withDRG seed $ do-      sk <- detSecretKeyDo-      sign sk (one byteToSign)  instance NFData Signature where   rnf (Signature (ECDSA.Signature a b)) = rnf a `seq` rnf b
+ src/Util/Num.hs view
@@ -0,0 +1,19 @@+-- SPDX-FileCopyrightText: 2020 Tocqueville Group+--+-- SPDX-License-Identifier: LicenseRef-MIT-TQ++-- | Utilities for numbers.+module Util.Num+  ( fromIntegralChecked+  ) where++-- | Convert between integral types, checking for overflows/underflows.+fromIntegralChecked :: (Integral a, Integral b) => a -> Either Text b+fromIntegralChecked a =+  let b = fromIntegral a+  in if toInteger a == toInteger b+    then Right b+    else Left+      if toInteger a > toInteger b+        then "Numeric overflow"+        else "Numeric underflow"
− src/Util/Test/Arbitrary.hs
@@ -1,241 +0,0 @@--- SPDX-FileCopyrightText: 2020 Tocqueville Group------ SPDX-License-Identifier: LicenseRef-MIT-TQ--{-# OPTIONS_GHC -Wno-orphans #-}--module Util.Test.Arbitrary-  ( runGen-  ) where--import Prelude hiding (EQ, GT, LT)--import Test.QuickCheck-  (Arbitrary(..), Gen, choose, elements, frequency, oneof, resize, suchThatMap, vector)-import Test.QuickCheck.Arbitrary.ADT (ToADTArbitrary(..))-import Test.QuickCheck.Gen (unGen)-import Test.QuickCheck.Instances.ByteString ()-import Test.QuickCheck.Instances.Natural ()-import Test.QuickCheck.Instances.Semigroup ()-import Test.QuickCheck.Instances.Text ()-import Test.QuickCheck.Random (mkQCGen)--import Michelson.ErrorPos (InstrCallStack(..), LetName(..), Pos(..), SrcPos(..))-import Michelson.Untyped-  (Annotation, Contract'(..), Elt(..), EntriesOrder(..), ExpandedExtInstr, ExpandedOp(..),-  ExtInstrAbstract(..), InstrAbstract(..), InternalByteString(..), ParameterType(..),-  StackTypePattern(..), T(..), TyVar(..), Type(..), Value'(..), Var(..), mkAnnotation)-import Tezos.Core (Mutez(..))--instance Arbitrary InternalByteString where-  arbitrary = InternalByteString <$> arbitrary--instance Arbitrary Var where-  arbitrary = Var <$> arbitrary--instance Arbitrary TyVar where-  arbitrary = oneof [VarID <$> arbitrary, TyCon <$> arbitrary]--instance Arbitrary StackTypePattern where-  arbitrary = oneof [pure StkEmpty, pure StkRest, StkCons <$> arbitrary <*> arbitrary]---- TODO extend Arbitrary ExpandedExtInstr with other constructors-instance Arbitrary ExpandedExtInstr where-  arbitrary = oneof [STACKTYPE <$> arbitrary]--instance ToADTArbitrary Pos-instance Arbitrary Pos where-  arbitrary = Pos <$> arbitrary--instance ToADTArbitrary SrcPos-instance Arbitrary SrcPos where-  arbitrary = liftA2 SrcPos arbitrary arbitrary--instance ToADTArbitrary LetName-instance Arbitrary LetName where-  arbitrary = LetName <$> resize 3 arbitrary--instance ToADTArbitrary InstrCallStack-instance Arbitrary InstrCallStack where-  arbitrary = liftA2 InstrCallStack genName arbitrary-    where-    genName = frequency [(80, pure []), (18, vector 1), (2, vector 2)]--instance ToADTArbitrary ExpandedOp-instance Arbitrary ExpandedOp where-  arbitrary = liftA2 WithSrcEx arbitrary (PrimEx <$> arbitrary)--instance ToADTArbitrary Mutez--instance ToADTArbitrary (Annotation tag)-instance Arbitrary (Annotation tag) where-  arbitrary = resize 5 arbitrary `suchThatMap` (rightToMaybe . mkAnnotation)--smallSize :: Gen Int-smallSize = choose (0, 3)--smallList :: Arbitrary a => Gen [a]-smallList = smallSize >>= vector--smallList1 :: Arbitrary a => Gen (NonEmpty a)-smallList1 = smallList `suchThatMap` nonEmpty--instance Arbitrary EntriesOrder where-  arbitrary = elements [minBound .. maxBound]--instance (Arbitrary op, ToADTArbitrary op) => ToADTArbitrary (Contract' op)-instance (Arbitrary op) => Arbitrary (Contract' op) where-  arbitrary = Contract <$> arbitrary <*> arbitrary <*> smallList <*> arbitrary--instance (Arbitrary op, ToADTArbitrary op, Arbitrary (ExtInstrAbstract op)) => ToADTArbitrary (InstrAbstract op)-instance (Arbitrary op, Arbitrary (ExtInstrAbstract op)) => Arbitrary (InstrAbstract op) where-  arbitrary =-    oneof-      [ EXT <$> arbitrary-      , pure DROP-      , DUP <$> arbitrary-      , pure SWAP-      , PUSH <$> arbitrary <*> arbitrary <*> arbitrary-      , SOME <$> arbitrary <*> arbitrary-      , NONE <$> arbitrary <*> arbitrary <*> arbitrary-      , UNIT <$> arbitrary <*> arbitrary-      , IF_NONE <$> smallList <*> smallList-      , PAIR <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-      , CAR <$> arbitrary <*> arbitrary-      , CDR <$> arbitrary <*> arbitrary-      , LEFT <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-      , RIGHT <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-      , IF_LEFT <$> smallList <*> smallList-      , NIL <$> arbitrary <*> arbitrary <*> arbitrary-      , CONS <$> arbitrary-      , IF_CONS <$> smallList <*> smallList-      , SIZE <$> arbitrary-      , EMPTY_SET <$> arbitrary <*> arbitrary <*> arbitrary-      , EMPTY_MAP <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-      , EMPTY_BIG_MAP <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-      , MAP <$> arbitrary <*> smallList-      , ITER <$> smallList-      , MEM <$> arbitrary-      , GET <$> arbitrary-      , UPDATE <$> arbitrary-      , IF <$> smallList <*> smallList-      , LOOP <$> smallList-      , LOOP_LEFT <$> smallList-      , LAMBDA <$> arbitrary <*> arbitrary <*> arbitrary <*> smallList-      , EXEC <$> arbitrary-      , APPLY <$> arbitrary-      , DIP <$> smallList-      , pure FAILWITH-      , CAST <$> arbitrary <*> arbitrary-      , RENAME <$> arbitrary-      , PACK <$> arbitrary-      , UNPACK <$> arbitrary <*> arbitrary <*> arbitrary-      , CONCAT <$> arbitrary-      , SLICE <$> arbitrary-      , ISNAT <$> arbitrary-      , ADD <$> arbitrary-      , SUB <$> arbitrary-      , MUL <$> arbitrary-      , EDIV <$> arbitrary-      , ABS <$> arbitrary-      , NEG <$> arbitrary-      , LSL <$> arbitrary-      , LSR <$> arbitrary-      , OR <$> arbitrary-      , AND <$> arbitrary-      , XOR <$> arbitrary-      , NOT <$> arbitrary-      , COMPARE <$> arbitrary-      , EQ <$> arbitrary-      , NEQ <$> arbitrary-      , LT <$> arbitrary-      , GT <$> arbitrary-      , LE <$> arbitrary-      , GE <$> arbitrary-      , INT <$> arbitrary-      , SELF <$> arbitrary <*> arbitrary-      , CONTRACT <$> arbitrary <*> arbitrary <*> arbitrary-      , TRANSFER_TOKENS <$> arbitrary-      , SET_DELEGATE <$> arbitrary-      , CREATE_CONTRACT <$> arbitrary <*> arbitrary <*> arbitrary-      , IMPLICIT_ACCOUNT <$> arbitrary-      , NOW <$> arbitrary-      , AMOUNT <$> arbitrary-      , BALANCE <$> arbitrary-      , CHECK_SIGNATURE <$> arbitrary-      , SHA256 <$> arbitrary-      , SHA512 <$> arbitrary-      , BLAKE2B <$> arbitrary-      , HASH_KEY <$> arbitrary-      , SOURCE <$> arbitrary-      , SENDER <$> arbitrary-      , ADDRESS <$> arbitrary-      ]--instance (Arbitrary op, ToADTArbitrary op) => ToADTArbitrary (Value' op)-instance (Arbitrary op) => Arbitrary (Value' op) where-  arbitrary =-    oneof-      [ ValueInt <$> arbitrary-      , ValueString <$> arbitrary-      , ValueBytes <$> arbitrary-      , pure ValueUnit-      , pure ValueTrue-      , pure ValueFalse-      , ValuePair <$> arbitrary <*> arbitrary-      , ValueLeft <$> arbitrary-      , ValueRight <$> arbitrary-      , ValueSome <$> arbitrary-      , pure ValueNone-      , pure ValueNil-      , ValueSeq <$> smallList1-      , ValueMap <$> smallList1-      , ValueLambda <$> smallList1-      ]--instance (Arbitrary op, ToADTArbitrary op) => ToADTArbitrary (Elt op)-instance (Arbitrary op) => Arbitrary (Elt op) where-  arbitrary = Elt <$> arbitrary <*> arbitrary--instance ToADTArbitrary Type-instance Arbitrary Type where-  arbitrary = Type <$> arbitrary <*> arbitrary--instance ToADTArbitrary ParameterType-instance Arbitrary ParameterType where-  arbitrary = ParameterType <$> arbitrary <*> arbitrary---- | @getRareT k@ generates 'T' producing anything big once per @1 / (k + 1)@--- invocation.-genRareType :: Word -> Gen Type-genRareType k = Type <$> genRareT k <*> arbitrary--instance ToADTArbitrary T-instance Arbitrary T where-  arbitrary =-    oneof-      [ pure TKey-      , pure TUnit-      , pure TSignature-      , TOption <$> arbitrary-      , TList <$> arbitrary-      , TSet <$> arbitrary-      , pure TOperation-      , TContract <$> arbitrary-      , TPair <$> arbitrary <*> arbitrary <*> genRareType 5 <*> genRareType 5-      , TOr <$> arbitrary <*> arbitrary <*> genRareType 5 <*> genRareType 5-      , TLambda <$> genRareType 5 <*> genRareType 5-      , TMap <$> arbitrary <*> arbitrary-      , TBigMap <$> arbitrary <*> arbitrary-      ]---- | @getRareT k@ generates 'Type' producing anything big once per @1 / (k + 1)@--- invocation.------ Useful to avoid exponensial growth.-genRareT :: Word -> Gen T-genRareT k = frequency [(1, arbitrary), (fromIntegral k, pure TUnit)]---- | Run given generator deterministically.-runGen :: Int -> Gen a -> a-runGen seed gen = unGen gen (mkQCGen seed) 10
src/Util/Type.hs view
@@ -37,13 +37,13 @@   ) where  import Data.Constraint ((:-)(..), Dict(..))-import Data.Vinyl.Core (Rec (..))-import qualified Data.Vinyl.Functor as Vinyl-import Data.Vinyl.Recursive (recordToList, rmap)-import Data.Vinyl.TypeLevel (type (++)) import qualified Data.Kind as Kind import Data.Type.Bool (type (&&), If, Not) import Data.Type.Equality (type (==))+import Data.Vinyl.Core (Rec(..))+import qualified Data.Vinyl.Functor as Vinyl+import Data.Vinyl.Recursive (recordToList, rmap)+import Data.Vinyl.TypeLevel (type (++)) import GHC.TypeLits (ErrorMessage(..), Symbol, TypeError) import Unsafe.Coerce (unsafeCoerce)