morley 1.14.0 → 1.15.0
raw patch · 84 files changed
+4611/−3468 lines, 84 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Michelson.FailPattern: class (Typeable a, ConstantScope a) => ConstantScope' a
- Michelson.FailPattern: instance (Data.Typeable.Internal.Typeable a, Michelson.Typed.Scope.ConstantScope a) => Michelson.FailPattern.ConstantScope' a
- Michelson.Interpret.Pack: encodeEpAddress :: EpAddress -> LByteString
- Michelson.Interpret.Pack: encodeIntPayload :: Integer -> LByteString
- Michelson.Interpret.Pack: encodeKeyHashRaw :: KeyHash -> LByteString
- Michelson.Interpret.Pack: encodeValue :: forall t. (SingI t, HasNoOp t) => Value t -> LByteString
- Michelson.Interpret.Pack: encodeValue' :: (SingI t, HasNoOp t) => Value t -> ByteString
- Michelson.Interpret.Pack: packCode' :: Instr inp out -> ByteString
- Michelson.Interpret.Pack: packNotedT' :: forall (t :: T). SingI t => Notes t -> ByteString
- Michelson.Interpret.Pack: packT' :: forall (t :: T). SingI t => ByteString
- Michelson.Interpret.Unpack: decodeContract :: Get Contract
- Michelson.Interpret.Unpack: decodeType :: Get Ty
- Michelson.Interpret.Unpack: unpackValue :: UnpackedValScope t => LByteString -> Either UnpackError (Value t)
- Michelson.Macro: UNPAIR :: UnpairStruct -> Macro
- Michelson.Macro: mapUnpairLeaves :: [(VarAnn, FieldAnn)] -> UnpairStruct -> UnpairStruct
- Michelson.Parser: UnknownTypeException :: CustomParserException
- Michelson.Parser.Annotations: notesTVF2 :: Parser (TypeAnn, VarAnn, (FieldAnn, FieldAnn))
- Michelson.Parser.Error: UnknownTypeException :: CustomParserException
- Michelson.Text: MTextUnsafe :: Text -> MText
- Michelson.Text: mkMTextUnsafe :: HasCallStack => Text -> MText
- Michelson.TypeCheck.TypeCheck: mkSomeParamTypeUnsafe :: HasCallStack => ParameterType -> SomeParamType
- Michelson.TypeCheck.TypeCheck: type TcResult inp = Either TCError (SomeInstr inp)
- Michelson.TypeCheck.Types: [SomeContractAndStorage] :: forall cp st. (StorageScope st, ParameterScope cp) => Contract cp st -> Value st -> SomeContractAndStorage
- Michelson.TypeCheck.Types: [SomeContract] :: Contract cp st -> SomeContract
- Michelson.TypeCheck.Types: data SomeContract
- Michelson.TypeCheck.Types: data SomeContractAndStorage
- Michelson.TypeCheck.Types: instance Control.DeepSeq.NFData Michelson.TypeCheck.Types.SomeContract
- Michelson.TypeCheck.Types: instance GHC.Show.Show Michelson.TypeCheck.Types.SomeContract
- Michelson.TypeCheck.Types: instance GHC.Show.Show Michelson.TypeCheck.Types.SomeContractAndStorage
- Michelson.Typed.Aliases: type SomeConstrainedValue = SomeConstrainedValue' Instr
- Michelson.Typed.Aliases: type SomeValue = SomeValue' Instr
- Michelson.Typed.Convert: instance Data.Typeable.Internal.Typeable s => GHC.Classes.Eq (Michelson.Typed.Instr.TestAssert s)
- Michelson.Typed.Entrypoints: EpNameUnsafe :: Text -> EpName
- Michelson.Typed.Entrypoints: ParamNotesUnsafe :: Notes t -> RootAnn -> ParamNotes (t :: T)
- Michelson.Typed.Entrypoints: epcCallRootUnsafe :: ParameterScope param => EntrypointCallT param param
- Michelson.Typed.Entrypoints: sepcCallRootUnsafe :: ParameterScope param => SomeEntrypointCallT param
- Michelson.Typed.Haskell: AnyIsoValue :: (forall a. IsoValue a => a) -> AnyIsoValue
- Michelson.Typed.Haskell: [SomeIsoValue] :: KnownIsoT a => a -> SomeIsoValue
- Michelson.Typed.Haskell: [unBigMap] :: BigMap k v -> Map k v
- Michelson.Typed.Haskell: class (Typeable t, SingI t) => KnownT (t :: T)
- Michelson.Typed.Haskell: concreteTypeDocHaskellRepUnsafe :: forall a b. (Typeable a, GenericIsoValue a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
- Michelson.Typed.Haskell: concreteTypeDocMichelsonRepUnsafe :: forall a b. (Typeable a, SingI (ToT a)) => TypeDocMichelsonRep b
- Michelson.Typed.Haskell: data SomeIsoValue
- Michelson.Typed.Haskell: instrGetField :: forall dt name st. InstrGetFieldC dt name => Label name -> Instr (ToT dt : st) (ToT (GetFieldType dt name) : st)
- Michelson.Typed.Haskell: instrUnwrapUnsafe :: forall dt name st. InstrUnwrapC dt name => Label name -> Instr (ToT dt : st) (ToT (CtorOnlyField name dt) : st)
- Michelson.Typed.Haskell: newtype AnyIsoValue
- Michelson.Typed.Haskell: newtype BigMap k v
- Michelson.Typed.Haskell.Doc: concreteTypeDocHaskellRepUnsafe :: forall a b. (Typeable a, GenericIsoValue a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
- Michelson.Typed.Haskell.Doc: concreteTypeDocMichelsonRepUnsafe :: forall a b. (Typeable a, SingI (ToT a)) => TypeDocMichelsonRep b
- Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.TypeHasDoc (Util.Named.ApplyNamedFunctor f a), GHC.TypeLits.KnownSymbol n, Data.Singletons.Internal.SingI (Michelson.Typed.Haskell.Value.ToT (Util.Named.ApplyNamedFunctor f GHC.Integer.Type.Integer)), Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable a) => Michelson.Typed.Haskell.Doc.TypeHasDoc (Named.Internal.NamedF f a n)
- Michelson.Typed.Haskell.Instr.Product: instrGetField :: forall dt name st. InstrGetFieldC dt name => Label name -> Instr (ToT dt : st) (ToT (GetFieldType dt name) : st)
- Michelson.Typed.Haskell.Instr.Sum: instrUnwrapUnsafe :: forall dt name st. InstrUnwrapC dt name => Label name -> Instr (ToT dt : st) (ToT (CtorOnlyField name dt) : st)
- Michelson.Typed.Haskell.LooseSum: instance (Data.Typeable.Internal.Typeable a, Michelson.Typed.Haskell.Value.IsoValue a) => Michelson.Typed.Haskell.LooseSum.GAccessField (GHC.Generics.Rec0 a)
- Michelson.Typed.Haskell.Value: AnyIsoValue :: (forall a. IsoValue a => a) -> AnyIsoValue
- Michelson.Typed.Haskell.Value: [SomeIsoValue] :: KnownIsoT a => a -> SomeIsoValue
- Michelson.Typed.Haskell.Value: [unBigMap] :: BigMap k v -> Map k v
- Michelson.Typed.Haskell.Value: class (Typeable t, SingI t) => KnownT (t :: T)
- Michelson.Typed.Haskell.Value: data SomeIsoValue
- Michelson.Typed.Haskell.Value: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Michelson.Typed.Haskell.Value.BigMap k v)
- Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Haskell.Value.WellTypedToT k, Michelson.Typed.Haskell.Value.WellTypedToT v, Michelson.Typed.Value.Comparable (Michelson.Typed.Haskell.Value.ToT k), GHC.Classes.Ord k, Michelson.Typed.Haskell.Value.IsoValue k, Michelson.Typed.Haskell.Value.IsoValue v) => Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.BigMap k v)
- Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Value.Comparable k, Michelson.Typed.Haskell.Value.WellTyped k, Michelson.Typed.Haskell.Value.WellTyped v) => Michelson.Typed.Haskell.Value.WellTyped ('Michelson.Typed.T.TBigMap k v)
- Michelson.Typed.Haskell.Value: instance GHC.Classes.Ord k => GHC.Base.Monoid (Michelson.Typed.Haskell.Value.BigMap k v)
- Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.WellTyped t => Michelson.Typed.Haskell.Value.WellTyped ('Michelson.Typed.T.TContract t)
- Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.WellTypedToT arg => Formatting.Buildable.Buildable (Michelson.Typed.Haskell.Value.ContractRef arg)
- Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.WellTypedToT arg => Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.ContractRef arg)
- Michelson.Typed.Haskell.Value: newtype AnyIsoValue
- Michelson.Typed.Haskell.Value: newtype BigMap k v
- Michelson.Typed.Scope: instance (Data.Singletons.Internal.SingI t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoBigMap t) => Michelson.Typed.Scope.PackedValScope t
- Michelson.Typed.Scope: instance (Data.Singletons.Internal.SingI t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoBigMap t, Michelson.Typed.Scope.HasNoContract t) => Michelson.Typed.Scope.ConstantScope t
- Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoBigMap t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoContract t a b, Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.ConstantScope t a b
- Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoBigMap t a b, Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.PackedValScope t a b
- Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoNestedBigMaps t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoContract t a b, Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.StorageScope t a b
- Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoNestedBigMaps t a b, Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.ParameterScope t a b
- Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.PackedValScope t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.ConstantScope t a b, Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.UnpackedValScope t a b
- Michelson.Typed.Scope: instance (Michelson.Typed.Sing.KnownT t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoNestedBigMaps t) => Michelson.Typed.Scope.ParameterScope t
- Michelson.Typed.Scope: instance (Michelson.Typed.Sing.KnownT t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoNestedBigMaps t, Michelson.Typed.Scope.HasNoContract t) => Michelson.Typed.Scope.StorageScope t
- Michelson.Typed.Scope: instance Michelson.Typed.Sing.KnownT t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.ConstantScope t)
- Michelson.Typed.Scope: instance Michelson.Typed.Sing.KnownT t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.PackedValScope t)
- Michelson.Typed.Scope: instance Michelson.Typed.Sing.KnownT t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.ParameterScope t)
- Michelson.Typed.Scope: instance Michelson.Typed.Sing.KnownT t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.StorageScope t)
- Michelson.Typed.Scope: instance Michelson.Typed.Sing.KnownT t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.UnpackedValScope t)
- Michelson.Typed.Sing: class (Typeable t, SingI t) => KnownT (t :: T)
- Michelson.Typed.Sing: fromSingT :: Sing (a :: T) -> T
- Michelson.Typed.Sing: instance (Data.Typeable.Internal.Typeable t, Data.Singletons.Internal.SingI t) => Michelson.Typed.Sing.KnownT t
- Michelson.Typed.Sing: instance (Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TBigMap a b)
- Michelson.Typed.Sing: instance (Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TLambda a b)
- Michelson.Typed.Sing: instance (Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TMap a b)
- Michelson.Typed.Sing: instance (Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TOr a b)
- Michelson.Typed.Sing: instance (Michelson.Typed.Sing.KnownT a, Michelson.Typed.Sing.KnownT b) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TPair a b)
- Michelson.Typed.Sing: instance Michelson.Typed.Sing.KnownT a => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TContract a)
- Michelson.Typed.Sing: instance Michelson.Typed.Sing.KnownT a => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TList a)
- Michelson.Typed.Sing: instance Michelson.Typed.Sing.KnownT a => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TOption a)
- Michelson.Typed.Sing: instance Michelson.Typed.Sing.KnownT a => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TSet a)
- Michelson.Typed.Sing: withSomeSingT :: T -> (forall (a :: T). KnownT a => Sing a -> r) -> r
- Michelson.Typed.Util: dfsFoldValue :: Monoid x => (forall t'. Value t' -> x) -> Value t -> x
- Michelson.Typed.Util: dfsModifyValue :: (forall t'. Value t' -> Value t') -> Value t -> Value t
- Michelson.Typed.Util: dfsValue :: forall t x. Monoid x => (forall t'. Value t' -> (Value t', x)) -> Value t -> (Value t, x)
- Michelson.Typed.Value: [SomeConstrainedValue] :: forall (t :: T) (c :: T -> Constraint) instr. c t => Value' instr t -> SomeConstrainedValue' instr c
- Michelson.Typed.Value: [SomeValue] :: KnownT t => Value' instr t -> SomeValue' instr
- Michelson.Typed.Value: data SomeConstrainedValue' instr (c :: T -> Constraint)
- Michelson.Typed.Value: data SomeValue' instr
- Michelson.Typed.Value: instance GHC.Classes.Eq (Michelson.Typed.Value.SomeValue' instr)
- Michelson.Typed.Value: instance GHC.Show.Show (Michelson.Typed.Value.SomeConstrainedValue' instr c)
- Michelson.Typed.Value: instance GHC.Show.Show (Michelson.Typed.Value.SomeValue' instr)
- Michelson.Typed.Value: instance Michelson.Typed.Sing.KnownT t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Value.ComparabilityScope t)
- Michelson.Untyped.Annotation: AnnotationUnsafe :: Text -> Annotation tag
- Michelson.Untyped.Annotation: mkAnnotationUnsafe :: HasCallStack => Text -> Annotation a
- Michelson.Untyped.Entrypoints: EpNameUnsafe :: Text -> EpName
- Michelson.Untyped.Instr: OperationHash :: ByteString -> OperationHash
- Michelson.Untyped.Instr: [unOperationHash] :: OperationHash -> ByteString
- Michelson.Untyped.Instr: newtype OperationHash
- Morley.Micheline.Class: instance (Michelson.Typed.Sing.KnownT inp, Michelson.Typed.Sing.KnownT out) => Morley.Micheline.Class.FromExpression (Michelson.Typed.Instr.Instr '[inp] '[out])
- Morley.Micheline.Class: instance Michelson.Typed.Scope.UnpackedValScope t => Morley.Micheline.Class.FromExpression (Michelson.Typed.Aliases.Value t)
- Morley.Micheline.Class: instance Morley.Micheline.Class.FromExpression [Michelson.Untyped.Instr.ExpandedOp]
- Tezos.Address: OperationHash :: ByteString -> OperationHash
- Tezos.Address: [unOperationHash] :: OperationHash -> ByteString
- Tezos.Address: instance Control.DeepSeq.NFData Tezos.Address.OperationHash
- Tezos.Address: instance GHC.Classes.Eq Tezos.Address.OperationHash
- Tezos.Address: instance GHC.Classes.Ord Tezos.Address.OperationHash
- Tezos.Address: instance GHC.Generics.Generic Tezos.Address.OperationHash
- Tezos.Address: instance GHC.Show.Show Tezos.Address.OperationHash
- Tezos.Address: mkContractAddress :: OperationHash -> OriginationIndex -> GlobalCounter -> Address
- Tezos.Address: newtype OperationHash
- Tezos.Core: ChainIdUnsafe :: ByteString -> ChainId
- Tezos.Core: data Mutez
- Tezos.Core: mkChainIdUnsafe :: HasCallStack => ByteString -> ChainId
- Tezos.Crypto: parseKeyHashUnsafe :: HasCallStack => Text -> KeyHash
- Tezos.Crypto.BLS12381: fromMichelsonBytesUnsafe :: (CurveObject a, HasCallStack) => ByteString -> a
- Tezos.Crypto.BLS12381: readFromHexUnsafe :: (CurveObject a, HasCallStack) => String -> a
- Util.Peano: class KnownPeano (n :: Peano)
- Util.Peano: instance (Data.Singletons.Internal.SingI n, Util.Peano.KnownPeano n) => Data.Singletons.Internal.SingI ('Data.Vinyl.TypeLevel.S n)
- Util.Peano: instance Util.Peano.KnownPeano 'Data.Vinyl.TypeLevel.Z
- Util.Peano: instance Util.Peano.KnownPeano a => Util.Peano.KnownPeano ('Data.Vinyl.TypeLevel.S a)
- Util.Peano: instance Util.Peano.KnownPeano a => Util.Type.MockableConstraint (Util.Peano.KnownPeano a)
- Util.Peano: peanoVal :: KnownPeano n => proxy n -> Natural
- Util.Peano: peanoVal' :: forall n. KnownPeano n => Natural
- Util.Peano: peanoValSing :: forall n. KnownPeano n => Sing n -> Natural
- Util.Positive: PositiveUnsafe :: Natural -> Positive
- Util.Type: provideConstraintUnsafe :: MockableConstraint c => Dict c
- Util.Typeable: eqP :: (Typeable a, Typeable b) => Proxy a -> Proxy b -> Maybe (a :~: b)
- Util.Typeable: gcastE :: forall a b t. (Typeable a, Typeable b) => t a -> Either Text (t b)
+ Michelson.ErrorPos: instance Michelson.Printer.Util.RenderDoc Michelson.ErrorPos.InstrCallStack
+ Michelson.Interpret: [isBigMapCounter] :: InterpreterState -> BigMapCounter
+ Michelson.Interpret: assignBigMapIds :: MonadState BigMapCounter m => Value t -> m (Value t)
+ Michelson.Interpret.Pack: toBinary :: ToExpression a => a -> LByteString
+ Michelson.Interpret.Pack: toBinary' :: ToExpression a => a -> ByteString
+ Michelson.Interpret.Unpack: unpackUValue' :: ByteString -> Either UnpackError Value
+ Michelson.Macro: UNPAPAIR :: UnpairStruct -> Macro
+ Michelson.Parser: parseExpandValueFromFile :: FilePath -> Text -> Either ParserException Value
+ Michelson.Parser: parseValueFromFile :: FilePath -> Text -> Either ParserException ParsedValue
+ Michelson.Parser.Annotations: notesVVFF :: Parser ((VarAnn, VarAnn), (FieldAnn, FieldAnn))
+ Michelson.Parser.Instr: unpairOp :: Parser ParsedInstr
+ Michelson.Printer: renderAnyBuildable :: Buildable a => a -> Doc
+ Michelson.Printer.Util: buildRenderDocExtended :: RenderDoc a => a -> Builder
+ Michelson.Printer.Util: renderAnyBuildable :: Buildable a => a -> Doc
+ Michelson.Printer.Util: renderDocList :: RenderDoc a => RenderContext -> [a] -> Doc
+ Michelson.Runtime: EEWrongParameterType :: a -> ExecutorError' a
+ Michelson.Runtime.Dummy: dummyBigMapCounter :: BigMapCounter
+ Michelson.Runtime.GState: BigMapCounter :: Natural -> BigMapCounter
+ Michelson.Runtime.GState: [GSSetBigMapCounter] :: BigMapCounter -> GStateUpdate
+ Michelson.Runtime.GState: [_bigMapCounter] :: BigMapCounter -> Natural
+ Michelson.Runtime.GState: [gsBigMapCounter] :: GState -> BigMapCounter
+ Michelson.Runtime.GState: bigMapCounter :: Iso' BigMapCounter Natural
+ Michelson.Runtime.GState: gsBigMapCounterL :: Lens' GState BigMapCounter
+ Michelson.Runtime.GState: instance Control.DeepSeq.NFData Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: instance Data.Aeson.Types.FromJSON.FromJSON Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: instance Data.Aeson.Types.ToJSON.ToJSON Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: instance Formatting.Buildable.Buildable Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: instance GHC.Classes.Eq Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: instance GHC.Generics.Generic Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: instance GHC.Num.Num Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: instance GHC.Show.Show Michelson.Runtime.GState.BigMapCounter
+ Michelson.Runtime.GState: newtype BigMapCounter
+ Michelson.Runtime.Import: ICEParse :: FilePath -> ParserException -> ImportContractError
+ Michelson.Runtime.Import: ICETypeCheck :: FilePath -> TCError -> ImportContractError
+ Michelson.Runtime.Import: IVEParse :: FilePath -> ParserException -> ImportValueError
+ Michelson.Runtime.Import: IVETypeCheck :: FilePath -> TCError -> ImportValueError
+ Michelson.Runtime.Import: data ImportContractError
+ Michelson.Runtime.Import: data ImportValueError
+ Michelson.Runtime.Import: importContract :: forall cp st. Each '[SingI] [cp, st] => FilePath -> IO (Contract cp st)
+ Michelson.Runtime.Import: importSomeContract :: FilePath -> IO SomeContract
+ Michelson.Runtime.Import: importSomeValue :: Ty -> FilePath -> IO SomeValue
+ Michelson.Runtime.Import: importUntypedContract :: FilePath -> IO Contract
+ Michelson.Runtime.Import: importUntypedValue :: FilePath -> IO Value
+ Michelson.Runtime.Import: importUsing :: Exception e => (FilePath -> Text -> Either e a) -> FilePath -> IO a
+ Michelson.Runtime.Import: importValue :: forall t. SingI t => FilePath -> IO (Value t)
+ Michelson.Runtime.Import: instance Formatting.Buildable.Buildable Michelson.Runtime.Import.ImportContractError
+ Michelson.Runtime.Import: instance Formatting.Buildable.Buildable Michelson.Runtime.Import.ImportValueError
+ Michelson.Runtime.Import: instance GHC.Classes.Eq Michelson.Runtime.Import.ImportContractError
+ Michelson.Runtime.Import: instance GHC.Classes.Eq Michelson.Runtime.Import.ImportValueError
+ Michelson.Runtime.Import: instance GHC.Exception.Type.Exception Michelson.Runtime.Import.ImportContractError
+ Michelson.Runtime.Import: instance GHC.Exception.Type.Exception Michelson.Runtime.Import.ImportValueError
+ Michelson.Runtime.Import: instance GHC.Show.Show Michelson.Runtime.Import.ImportContractError
+ Michelson.Runtime.Import: instance GHC.Show.Show Michelson.Runtime.Import.ImportValueError
+ Michelson.Runtime.Import: readContract :: forall cp st. Each '[SingI] [cp, st] => FilePath -> Text -> Either ImportContractError (Contract cp st)
+ Michelson.Runtime.Import: readSomeContract :: FilePath -> Text -> Either ImportContractError SomeContract
+ Michelson.Runtime.Import: readUntypedContract :: FilePath -> Text -> Either ImportContractError Contract
+ Michelson.Runtime.Import: readValue :: forall t. SingI t => FilePath -> Text -> Either ImportValueError (Value t)
+ Michelson.Text: UnsafeMText :: Text -> MText
+ Michelson.Text: unsafeMkMText :: HasCallStack => Text -> MText
+ Michelson.TypeCheck: typeCheckTopLevelType :: Maybe TcOriginatedContracts -> Ty -> Value -> TypeCheckResult SomeValue
+ Michelson.TypeCheck: typeVerifyContract :: forall cp st. (SingI cp, SingI st) => Contract -> TypeCheckResult (Contract cp st)
+ Michelson.TypeCheck: typeVerifyTopLevelType :: forall t. SingI t => Maybe TcOriginatedContracts -> Value -> TypeCheckResult (Value t)
+ Michelson.TypeCheck.Error: TicketsJoin :: TypeContext
+ Michelson.TypeCheck.Error: TltParameterType :: TopLevelType
+ Michelson.TypeCheck.Error: TltStorageType :: TopLevelType
+ Michelson.TypeCheck.Error: UnexpectedTopLevelType :: TopLevelType -> ("expected" :! T) -> ("got" :! T) -> TCTypeError
+ Michelson.TypeCheck.Error: UnpairArgument :: TypeContext
+ Michelson.TypeCheck.Error: data TopLevelType
+ Michelson.TypeCheck.Error: instance Control.DeepSeq.NFData Michelson.TypeCheck.Error.TopLevelType
+ Michelson.TypeCheck.Error: instance Formatting.Buildable.Buildable Michelson.TypeCheck.Error.TopLevelType
+ Michelson.TypeCheck.Error: instance GHC.Classes.Eq Michelson.TypeCheck.Error.TopLevelType
+ Michelson.TypeCheck.Error: instance GHC.Generics.Generic Michelson.TypeCheck.Error.TopLevelType
+ Michelson.TypeCheck.Error: instance GHC.Show.Show Michelson.TypeCheck.Error.TopLevelType
+ Michelson.TypeCheck.Error: instance Michelson.Printer.Util.RenderDoc Michelson.TypeCheck.Error.TCError
+ Michelson.TypeCheck.Error: instance Michelson.Printer.Util.RenderDoc Michelson.TypeCheck.Error.TCTypeError
+ Michelson.TypeCheck.Error: instance Michelson.Printer.Util.RenderDoc Michelson.TypeCheck.Error.TopLevelType
+ Michelson.TypeCheck.Error: instance Michelson.Printer.Util.RenderDoc Michelson.TypeCheck.Error.TypeContext
+ Michelson.TypeCheck.Instr: typeCheckTopLevelType :: Maybe TcOriginatedContracts -> Ty -> Value -> TypeCheckResult SomeValue
+ Michelson.TypeCheck.Instr: typeVerifyContract :: forall cp st. (SingI cp, SingI st) => Contract -> TypeCheckResult (Contract cp st)
+ Michelson.TypeCheck.Instr: typeVerifyTopLevelType :: forall t. SingI t => Maybe TcOriginatedContracts -> Value -> TypeCheckResult (Value t)
+ Michelson.TypeCheck.TypeCheck: [tcStrict] :: TypeCheckOptions -> Bool
+ Michelson.TypeCheck.TypeCheck: type TypeCheckResult = (ReaderT TypeCheckOptions (Except TCError))
+ Michelson.TypeCheck.TypeCheck: typeCheckingWith :: TypeCheckOptions -> TypeCheckResult a -> Either TCError a
+ Michelson.TypeCheck.TypeCheck: unsafeMkSomeParamType :: HasCallStack => ParameterType -> SomeParamType
+ Michelson.TypeCheck.Types: [nwtBadType] :: NotWellTyped -> T
+ Michelson.TypeCheck.Types: [nwtCause] :: NotWellTyped -> BadTypeForScope
+ Michelson.TypeCheck.Types: getWTP_ :: forall t. Sing t -> Either NotWellTyped (Dict (WellTyped t))
+ Michelson.TypeCheck.Types: instance Michelson.Printer.Util.RenderDoc (Michelson.TypeCheck.Types.HST ts)
+ Michelson.Typed.Annotation: [NTTicket] :: TypeAnn -> Notes t -> Notes ('TTicket t)
+ Michelson.Typed.Convert: instance Data.Singletons.Internal.SingI s => GHC.Classes.Eq (Michelson.Typed.Instr.TestAssert s)
+ Michelson.Typed.Convert: instance GHC.Classes.Eq Michelson.Typed.Convert.UntypingOptions
+ Michelson.Typed.Convert: instance GHC.Show.Show Michelson.Typed.Convert.UntypingOptions
+ Michelson.Typed.Convert: instrToOpsOptimized :: HasCallStack => Instr inp out -> [ExpandedOp]
+ Michelson.Typed.Convert: untypeValueHashable :: (SingI t, HasNoOp t) => Value' Instr t -> Value
+ Michelson.Typed.Convert: untypeValueOptimized :: (SingI t, HasNoOp t) => Value' Instr t -> Value
+ Michelson.Typed.Doc: instance Michelson.Doc.ContainsDoc (Michelson.Typed.Instr.Contract cp st)
+ Michelson.Typed.Doc: instance Michelson.Doc.ContainsUpdateableDoc (Michelson.Typed.Instr.Contract cp st)
+ Michelson.Typed.Entrypoints: UnsafeEpName :: Text -> EpName
+ Michelson.Typed.Entrypoints: UnsafeParamNotes :: Notes t -> RootAnn -> ParamNotes (t :: T)
+ Michelson.Typed.Entrypoints: instance Michelson.Printer.Util.RenderDoc Michelson.Typed.Entrypoints.ArmCoord
+ Michelson.Typed.Entrypoints: instance Michelson.Printer.Util.RenderDoc Michelson.Typed.Entrypoints.ParamEpError
+ Michelson.Typed.Entrypoints: instance Michelson.Printer.Util.RenderDoc Michelson.Typed.Entrypoints.ParseEpAddressError
+ Michelson.Typed.Entrypoints: unsafeEpcCallRoot :: ParameterScope param => EntrypointCallT param param
+ Michelson.Typed.Entrypoints: unsafeSepcCallRoot :: ParameterScope param => SomeEntrypointCallT param
+ Michelson.Typed.Existential: [SomeConstant] :: (ConstantScope t, SingI t) => Value t -> SomeConstant
+ Michelson.Typed.Existential: [SomeConstrainedValue] :: forall (t :: T) (c :: T -> Constraint). c t => Value t -> SomeConstrainedValue c
+ Michelson.Typed.Existential: [SomeContractAndStorage] :: forall cp st. (StorageScope st, ParameterScope cp) => Contract cp st -> Value st -> SomeContractAndStorage
+ Michelson.Typed.Existential: [SomeContract] :: Contract cp st -> SomeContract
+ Michelson.Typed.Existential: [SomeIsoValue] :: KnownIsoT a => a -> SomeIsoValue
+ Michelson.Typed.Existential: [SomeStorage] :: forall st. StorageScope st => Value st -> SomeStorage
+ Michelson.Typed.Existential: [SomeValue] :: SingI t => Value t -> SomeValue
+ Michelson.Typed.Existential: data SomeConstant
+ Michelson.Typed.Existential: data SomeConstrainedValue (c :: T -> Constraint)
+ Michelson.Typed.Existential: data SomeContract
+ Michelson.Typed.Existential: data SomeContractAndStorage
+ Michelson.Typed.Existential: data SomeIsoValue
+ Michelson.Typed.Existential: data SomeStorage
+ Michelson.Typed.Existential: data SomeValue
+ Michelson.Typed.Existential: instance Control.DeepSeq.NFData Michelson.Typed.Existential.SomeContract
+ Michelson.Typed.Existential: instance Formatting.Buildable.Buildable Michelson.Typed.Existential.SomeConstant
+ Michelson.Typed.Existential: instance GHC.Classes.Eq Michelson.Typed.Existential.SomeValue
+ Michelson.Typed.Existential: instance GHC.Show.Show (Michelson.Typed.Existential.SomeConstrainedValue c)
+ Michelson.Typed.Existential: instance GHC.Show.Show Michelson.Typed.Existential.SomeContract
+ Michelson.Typed.Existential: instance GHC.Show.Show Michelson.Typed.Existential.SomeContractAndStorage
+ Michelson.Typed.Existential: instance GHC.Show.Show Michelson.Typed.Existential.SomeStorage
+ Michelson.Typed.Existential: instance GHC.Show.Show Michelson.Typed.Existential.SomeValue
+ Michelson.Typed.Haskell: BigMapId :: Natural -> BigMapId k v
+ Michelson.Typed.Haskell: Ticket :: Address -> arg -> Natural -> Ticket (arg :: Type)
+ Michelson.Typed.Haskell: [bmId] :: BigMap k v -> Maybe (BigMapId k v)
+ Michelson.Typed.Haskell: [bmMap] :: BigMap k v -> Map k v
+ Michelson.Typed.Haskell: [tAmount] :: Ticket (arg :: Type) -> Natural
+ Michelson.Typed.Haskell: [tData] :: Ticket (arg :: Type) -> arg
+ Michelson.Typed.Haskell: [tTicketer] :: Ticket (arg :: Type) -> Address
+ Michelson.Typed.Haskell: [unBigMapId] :: BigMapId k v -> Natural
+ Michelson.Typed.Haskell: data BigMap k v
+ Michelson.Typed.Haskell: data Ticket (arg :: Type)
+ Michelson.Typed.Haskell: instrToField :: forall dt name st. InstrGetFieldC dt name => Label name -> Instr (ToT dt : st) (ToT (GetFieldType dt name) : st)
+ Michelson.Typed.Haskell: mkBigMap :: Ord k => [(k, v)] -> BigMap k v
+ Michelson.Typed.Haskell: newtype BigMapId k v
+ Michelson.Typed.Haskell: type HasNoOpToT a = HasNoOp (ToT a)
+ Michelson.Typed.Haskell: unsafeConcreteTypeDocHaskellRep :: forall a b. (Typeable a, GenericIsoValue a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
+ Michelson.Typed.Haskell: unsafeConcreteTypeDocMichelsonRep :: forall a b. (Typeable a, KnownIsoT a) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell: unsafeInstrUnwrap :: forall dt name st. InstrUnwrapC dt name => Label name -> Instr (ToT dt : st) (ToT (CtorOnlyField name dt) : st)
+ Michelson.Typed.Haskell.Doc: instance (Michelson.Typed.Haskell.Doc.TypeHasDoc (Util.Named.ApplyNamedFunctor f a), GHC.TypeLits.KnownSymbol n, Michelson.Typed.Haskell.Value.KnownIsoT (Util.Named.ApplyNamedFunctor f GHC.Integer.Type.Integer), Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable a) => Michelson.Typed.Haskell.Doc.TypeHasDoc (Named.Internal.NamedF f a n)
+ Michelson.Typed.Haskell.Doc: instance Michelson.Typed.Haskell.Doc.PolyTypeHasDocC '[a] => Michelson.Typed.Haskell.Doc.TypeHasDoc (Michelson.Typed.Haskell.Value.Ticket a)
+ Michelson.Typed.Haskell.Doc: unsafeConcreteTypeDocHaskellRep :: forall a b. (Typeable a, GenericIsoValue a, GTypeHasDoc (Rep a)) => TypeDocHaskellRep b
+ Michelson.Typed.Haskell.Doc: unsafeConcreteTypeDocMichelsonRep :: forall a b. (Typeable a, KnownIsoT a) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell.Instr.Product: instrToField :: forall dt name st. InstrGetFieldC dt name => Label name -> Instr (ToT dt : st) (ToT (GetFieldType dt name) : st)
+ Michelson.Typed.Haskell.Instr.Sum: unsafeInstrUnwrap :: forall dt name st. InstrUnwrapC dt name => Label name -> Instr (ToT dt : st) (ToT (CtorOnlyField name dt) : st)
+ Michelson.Typed.Haskell.LooseSum: instance Michelson.Typed.Haskell.Value.IsoValue a => Michelson.Typed.Haskell.LooseSum.GAccessField (GHC.Generics.Rec0 a)
+ Michelson.Typed.Haskell.Value: BigMapId :: Natural -> BigMapId k v
+ Michelson.Typed.Haskell.Value: Ticket :: Address -> arg -> Natural -> Ticket (arg :: Type)
+ Michelson.Typed.Haskell.Value: [bmId] :: BigMap k v -> Maybe (BigMapId k v)
+ Michelson.Typed.Haskell.Value: [bmMap] :: BigMap k v -> Map k v
+ Michelson.Typed.Haskell.Value: [tAmount] :: Ticket (arg :: Type) -> Natural
+ Michelson.Typed.Haskell.Value: [tData] :: Ticket (arg :: Type) -> arg
+ Michelson.Typed.Haskell.Value: [tTicketer] :: Ticket (arg :: Type) -> Address
+ Michelson.Typed.Haskell.Value: [unBigMapId] :: BigMapId k v -> Natural
+ Michelson.Typed.Haskell.Value: data BigMap k v
+ Michelson.Typed.Haskell.Value: data Ticket (arg :: Type)
+ Michelson.Typed.Haskell.Value: instance (Data.Data.Data k, Data.Data.Data v, GHC.Classes.Ord k) => Data.Data.Data (Michelson.Typed.Haskell.Value.BigMap k v)
+ Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Haskell.Value.HasNoOpToT arg, Michelson.Typed.Haskell.Value.WellTypedToT arg) => Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.ContractRef arg)
+ Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Haskell.Value.WellTyped t, Michelson.Typed.Scope.HasNoOp t) => Michelson.Typed.Haskell.Value.WellTyped ('Michelson.Typed.T.TContract t)
+ Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Haskell.Value.WellTyped t, Michelson.Typed.Value.Comparable t) => Michelson.Typed.Haskell.Value.WellTyped ('Michelson.Typed.T.TTicket t)
+ Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Value.Comparable (Michelson.Typed.Haskell.Value.ToT a), Michelson.Typed.Haskell.Value.IsoValue a) => Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.Ticket a)
+ Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Value.Comparable (Michelson.Typed.Haskell.Value.ToT k), GHC.Classes.Ord k, Michelson.Typed.Haskell.Value.IsoValue k, Michelson.Typed.Haskell.Value.IsoValue v, Michelson.Typed.Haskell.Value.HasNoBigMapToT v, Michelson.Typed.Haskell.Value.HasNoOpToT v) => Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.BigMap k v)
+ Michelson.Typed.Haskell.Value: instance (Michelson.Typed.Value.Comparable k, Michelson.Typed.Haskell.Value.WellTyped k, Michelson.Typed.Haskell.Value.WellTyped v, Michelson.Typed.Scope.HasNoBigMap v, Michelson.Typed.Scope.HasNoOp v) => Michelson.Typed.Haskell.Value.WellTyped ('Michelson.Typed.T.TBigMap k v)
+ Michelson.Typed.Haskell.Value: instance Data.Foldable.Foldable (Michelson.Typed.Haskell.Value.BigMap k)
+ Michelson.Typed.Haskell.Value: instance GHC.Classes.Eq arg => GHC.Classes.Eq (Michelson.Typed.Haskell.Value.Ticket arg)
+ Michelson.Typed.Haskell.Value: instance GHC.Generics.Generic (Michelson.Typed.Haskell.Value.BigMap k v)
+ Michelson.Typed.Haskell.Value: instance GHC.Show.Show arg => GHC.Show.Show (Michelson.Typed.Haskell.Value.Ticket arg)
+ Michelson.Typed.Haskell.Value: instance Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.ContractRef arg) => Formatting.Buildable.Buildable (Michelson.Typed.Haskell.Value.ContractRef arg)
+ Michelson.Typed.Haskell.Value: instance forall k1 (k2 :: k1) k3 (v :: k3). (Data.Typeable.Internal.Typeable k2, Data.Typeable.Internal.Typeable v, Data.Typeable.Internal.Typeable k1, Data.Typeable.Internal.Typeable k3) => Data.Data.Data (Michelson.Typed.Haskell.Value.BigMapId k2 v)
+ Michelson.Typed.Haskell.Value: instance forall k1 (k2 :: k1) k3 (v :: k3). Formatting.Buildable.Buildable (Michelson.Typed.Haskell.Value.BigMapId k2 v)
+ Michelson.Typed.Haskell.Value: instance forall k1 (k2 :: k1) k3 (v :: k3). GHC.Num.Num (Michelson.Typed.Haskell.Value.BigMapId k2 v)
+ Michelson.Typed.Haskell.Value: instance forall k1 (k2 :: k1) k3 (v :: k3). GHC.Show.Show (Michelson.Typed.Haskell.Value.BigMapId k2 v)
+ Michelson.Typed.Haskell.Value: instance forall k1 (k2 :: k1) k3 (v :: k3). Michelson.Typed.Haskell.Value.IsoValue (Michelson.Typed.Haskell.Value.BigMapId k2 v)
+ Michelson.Typed.Haskell.Value: mkBigMap :: Ord k => [(k, v)] -> BigMap k v
+ Michelson.Typed.Haskell.Value: newtype BigMapId k v
+ Michelson.Typed.Haskell.Value: type HasNoOpToT a = HasNoOp (ToT a)
+ Michelson.Typed.Instr: STACKTYPE :: StackTypePattern -> ExtInstr s
+ Michelson.Typed.Instr: [AnnUNPAIR] :: VarAnn -> VarAnn -> FieldAnn -> FieldAnn -> Instr ('TPair a b : s) (a : (b : s))
+ Michelson.Typed.Instr: [Fn] :: Text -> StackFn -> Instr inp out -> Instr inp out
+ Michelson.Typed.Instr: [JOIN_TICKETS] :: Instr ('TPair ('TTicket a) ('TTicket a) : s) ('TOption ('TTicket a) : s)
+ Michelson.Typed.Instr: [READ_TICKET] :: Instr ('TTicket a : s) (RightComb ['TAddress, a, 'TNat] : ('TTicket a : s))
+ Michelson.Typed.Instr: [SPLIT_TICKET] :: Instr ('TTicket a : ('TPair 'TNat 'TNat : s)) ('TOption ('TPair ('TTicket a) ('TTicket a)) : s)
+ Michelson.Typed.Instr: [TICKET] :: Comparable a => Instr (a : ('TNat : s)) ('TTicket a : s)
+ Michelson.Typed.Instr: castInstr :: forall inp1 out1 inp2 out2. (SingI inp1, SingI out1, SingI inp2, SingI out2) => Instr inp1 out1 -> Maybe (Instr inp2 out2)
+ Michelson.Typed.Instr: infixr 8 :#
+ Michelson.Typed.Instr: pattern (:#) :: Instr a b -> Instr b c -> Instr a c
+ Michelson.Typed.Origination: OperationHash :: ByteString -> OperationHash
+ Michelson.Typed.Origination: [unOperationHash] :: OperationHash -> ByteString
+ Michelson.Typed.Origination: instance Control.DeepSeq.NFData Michelson.Typed.Origination.OperationHash
+ Michelson.Typed.Origination: instance GHC.Classes.Eq Michelson.Typed.Origination.OperationHash
+ Michelson.Typed.Origination: instance GHC.Classes.Ord Michelson.Typed.Origination.OperationHash
+ Michelson.Typed.Origination: instance GHC.Generics.Generic Michelson.Typed.Origination.OperationHash
+ Michelson.Typed.Origination: instance GHC.Show.Show Michelson.Typed.Origination.OperationHash
+ Michelson.Typed.Origination: mkContractAddress :: OperationHash -> OriginationIndex -> GlobalCounter -> Address
+ Michelson.Typed.Origination: newtype OperationHash
+ Michelson.Typed.Scope: BtHasTicket :: BadTypeForScope
+ Michelson.Typed.Scope: TicketAbsent :: TicketPresence (t :: T)
+ Michelson.Typed.Scope: TicketPresent :: TicketPresence (t :: T)
+ Michelson.Typed.Scope: checkTicketPresence :: Sing (ty :: T) -> TicketPresence ty
+ Michelson.Typed.Scope: class (SingI t, HasNoTicket t) => DupableScope t
+ Michelson.Typed.Scope: class (ContainsTicket t ~ 'False) => HasNoTicket t
+ Michelson.Typed.Scope: data TicketPresence (t :: T)
+ Michelson.Typed.Scope: instance (Data.Singletons.Internal.SingI t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoBigMap t, Michelson.Typed.Scope.HasNoContract t, Michelson.Typed.Scope.HasNoTicket t) => Michelson.Typed.Scope.ConstantScope t
+ Michelson.Typed.Scope: instance (Data.Singletons.Internal.SingI t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoBigMap t, Michelson.Typed.Scope.HasNoTicket t) => Michelson.Typed.Scope.PackedValScope t
+ Michelson.Typed.Scope: instance (Data.Singletons.Internal.SingI t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoNestedBigMaps t) => Michelson.Typed.Scope.ParameterScope t
+ Michelson.Typed.Scope: instance (Data.Singletons.Internal.SingI t, Michelson.Typed.Scope.HasNoOp t, Michelson.Typed.Scope.HasNoNestedBigMaps t, Michelson.Typed.Scope.HasNoContract t) => Michelson.Typed.Scope.StorageScope t
+ Michelson.Typed.Scope: instance (Data.Singletons.Internal.SingI t, Michelson.Typed.Scope.HasNoTicket t) => Michelson.Typed.Scope.DupableScope t
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.ContainsTicket t GHC.Types.~ 'GHC.Types.False) => Michelson.Typed.Scope.HasNoTicket t
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoBigMap t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoContract t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoTicket t a b, Data.Singletons.Internal.SingI a, Data.Singletons.Internal.SingI b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.ConstantScope t a b
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoBigMap t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoTicket t a b, Data.Singletons.Internal.SingI a, Data.Singletons.Internal.SingI b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.PackedValScope t a b
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoNestedBigMaps t a b, Data.Singletons.Internal.SingI a, Data.Singletons.Internal.SingI b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.ParameterScope t a b
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoOp t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoNestedBigMaps t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoContract t a b, Data.Singletons.Internal.SingI a, Data.Singletons.Internal.SingI b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.StorageScope t a b
+ Michelson.Typed.Scope: instance (Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.PackedValScope t a b, Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.ConstantScope t a b, Data.Singletons.Internal.SingI a, Data.Singletons.Internal.SingI b) => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.UnpackedValScope t a b
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI a => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoTicket 'Michelson.Typed.T.TOr a b
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI a => Michelson.Typed.Scope.WithDeMorganScope Michelson.Typed.Scope.HasNoTicket 'Michelson.Typed.T.TPair a b
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.ConstantScope t)
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.DupableScope t)
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.HasNoTicket t)
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.PackedValScope t)
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.ParameterScope t)
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.StorageScope t)
+ Michelson.Typed.Scope: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Scope.UnpackedValScope t)
+ Michelson.Typed.Scope: instance Michelson.Printer.Util.RenderDoc Michelson.Typed.Scope.BadTypeForScope
+ Michelson.Typed.Scope: properDupableEvi :: forall t. ProperDupableBetterErrors t :- DupableScope t
+ Michelson.Typed.Scope: type ForbidTicket t = FailOnTicketFound (ContainsTicket t)
+ Michelson.Typed.Scope: type ProperDupableBetterErrors t = (SingI t, ForbidTicket t)
+ Michelson.Typed.Sing: [STTicket] :: forall (n_a1EVE :: T). () => Sing n_a1EVE -> SingT ('TTicket n_a1EVE :: T)
+ Michelson.Typed.Sing: castM :: forall (a :: T) (b :: T) t m. (SingI a, SingI b, Monad m) => t a -> (forall x. Demote (KindOf a) -> Demote (KindOf b) -> m x) -> m (t b)
+ Michelson.Typed.Sing: castSingE :: forall (a :: T) (b :: T) t. (SingI a, SingI b) => t a -> Either Text (t b)
+ Michelson.Typed.Sing: eqP :: forall (a :: T) (b :: T). (SingI a, SingI b) => Proxy a -> Proxy b -> Maybe (a :~: b)
+ Michelson.Typed.Sing: instance (Data.Singletons.Internal.SingI n1, Data.Singletons.Internal.SingI n2) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TBigMap n1 n2)
+ Michelson.Typed.Sing: instance (Data.Singletons.Internal.SingI n1, Data.Singletons.Internal.SingI n2) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TLambda n1 n2)
+ Michelson.Typed.Sing: instance (Data.Singletons.Internal.SingI n1, Data.Singletons.Internal.SingI n2) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TMap n1 n2)
+ Michelson.Typed.Sing: instance (Data.Singletons.Internal.SingI n1, Data.Singletons.Internal.SingI n2) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TOr n1 n2)
+ Michelson.Typed.Sing: instance (Data.Singletons.Internal.SingI n1, Data.Singletons.Internal.SingI n2) => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TPair n1 n2)
+ Michelson.Typed.Sing: instance Data.Singletons.Decide.SDecide Michelson.Typed.T.T => Data.Singletons.Decide.SDecide Michelson.Typed.T.T
+ Michelson.Typed.Sing: instance Data.Singletons.Decide.SDecide Michelson.Typed.T.T => Data.Type.Coercion.TestCoercion Michelson.Typed.Sing.SingT
+ Michelson.Typed.Sing: instance Data.Singletons.Decide.SDecide Michelson.Typed.T.T => Data.Type.Equality.TestEquality Michelson.Typed.Sing.SingT
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TBigMapSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TContractSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TLambdaSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TListSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TMapSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TOptionSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TOrSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TPairSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TSetSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI Michelson.Typed.Sing.TTicketSym0
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI d => Data.Singletons.Internal.SingI (Michelson.Typed.Sing.TBigMapSym1 d)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI d => Data.Singletons.Internal.SingI (Michelson.Typed.Sing.TLambdaSym1 d)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI d => Data.Singletons.Internal.SingI (Michelson.Typed.Sing.TMapSym1 d)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI d => Data.Singletons.Internal.SingI (Michelson.Typed.Sing.TOrSym1 d)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI d => Data.Singletons.Internal.SingI (Michelson.Typed.Sing.TPairSym1 d)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI k => Util.Sing.SingI1 ('Michelson.Typed.T.TMap k)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI n => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TContract n)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI n => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TList n)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI n => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TOption n)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI n => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TSet n)
+ Michelson.Typed.Sing: instance Data.Singletons.Internal.SingI n => Data.Singletons.Internal.SingI ('Michelson.Typed.T.TTicket n)
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings (Michelson.Typed.Sing.TBigMapSym1 a6989586621679405431)
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings (Michelson.Typed.Sing.TLambdaSym1 a6989586621679405425)
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings (Michelson.Typed.Sing.TMapSym1 a6989586621679405428)
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings (Michelson.Typed.Sing.TOrSym1 a6989586621679405422)
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings (Michelson.Typed.Sing.TPairSym1 a6989586621679405419)
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TBigMapSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TContractSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TLambdaSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TListSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TMapSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TOptionSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TOrSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TPairSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TSetSym0
+ Michelson.Typed.Sing: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Michelson.Typed.Sing.TTicketSym0
+ Michelson.Typed.Sing: instance Util.Sing.SingI1 'Michelson.Typed.T.TList
+ Michelson.Typed.Sing: requireEq :: forall (a :: T) (b :: T) m. (SingI a, SingI b, Monad m) => (forall x. Demote (KindOf a) -> Demote (KindOf b) -> m x) -> m (a :~: b)
+ Michelson.Typed.T: TTicket :: T -> T
+ Michelson.Typed.T: instance Michelson.Printer.Util.RenderDoc Michelson.Typed.T.T
+ Michelson.Typed.Util: dfsFoldMapValue :: Monoid x => (forall t'. Value t' -> x) -> Value t -> x
+ Michelson.Typed.Util: dfsFoldMapValueM :: (Monoid x, Monad m) => (forall t'. Value t' -> m x) -> Value t -> m x
+ Michelson.Typed.Util: dfsMapValue :: forall t. (forall t'. Value t' -> Value t') -> Value t -> Value t
+ Michelson.Typed.Util: dfsTraverseValue :: forall t m. Monad m => (forall t'. Value t' -> m (Value t')) -> Value t -> m (Value t)
+ Michelson.Typed.Value: [VTicket] :: forall arg instr. Comparable arg => Address -> Value' instr arg -> Natural -> Value' instr ('TTicket arg)
+ Michelson.Typed.Value: instance Data.Singletons.Internal.SingI t => Michelson.Typed.Scope.CheckScope (Michelson.Typed.Value.ComparabilityScope t)
+ Michelson.Untyped.Annotation: AnnotationSet :: [TypeAnn] -> [FieldAnn] -> [VarAnn] -> AnnotationSet
+ Michelson.Untyped.Annotation: UnsafeAnnotation :: Text -> Annotation tag
+ Michelson.Untyped.Annotation: [asFields] :: AnnotationSet -> [FieldAnn]
+ Michelson.Untyped.Annotation: [asTypes] :: AnnotationSet -> [TypeAnn]
+ Michelson.Untyped.Annotation: [asVars] :: AnnotationSet -> [VarAnn]
+ Michelson.Untyped.Annotation: annsCount :: AnnotationSet -> (Int, Int, Int)
+ Michelson.Untyped.Annotation: firstAnn :: KnownAnnTag tag => AnnotationSet -> Annotation tag
+ Michelson.Untyped.Annotation: minimizeAnnSet :: AnnotationSet -> AnnotationSet
+ Michelson.Untyped.Annotation: secondAnn :: KnownAnnTag tag => AnnotationSet -> Annotation tag
+ Michelson.Untyped.Annotation: unsafeMkAnnotation :: HasCallStack => Text -> Annotation a
+ Michelson.Untyped.Entrypoints: UnsafeEpName :: Text -> EpName
+ Michelson.Untyped.Entrypoints: instance Michelson.Printer.Util.RenderDoc Michelson.Untyped.Entrypoints.EpNameFromRefAnnError
+ Michelson.Untyped.Instr: JOIN_TICKETS :: VarAnn -> InstrAbstract op
+ Michelson.Untyped.Instr: READ_TICKET :: VarAnn -> InstrAbstract op
+ Michelson.Untyped.Instr: SPLIT_TICKET :: VarAnn -> InstrAbstract op
+ Michelson.Untyped.Instr: TICKET :: VarAnn -> InstrAbstract op
+ Michelson.Untyped.Instr: UNPAIR :: VarAnn -> VarAnn -> FieldAnn -> FieldAnn -> InstrAbstract op
+ Michelson.Untyped.Type: TTicket :: Ty -> T
+ Michelson.Untyped.Value: linearizeRightCombValuePair :: Value' op -> NonEmpty (Value' op)
+ Morley.Micheline.Binary: encodeExpression' :: Expression -> ByteString
+ Morley.Micheline.Class: instance (Data.Singletons.Internal.SingI inp, Data.Singletons.Internal.SingI out) => Morley.Micheline.Class.FromExpression (Michelson.Typed.Instr.Instr '[inp] '[out])
+ Morley.Micheline.Class: instance Data.Singletons.Internal.SingI t => Morley.Micheline.Class.FromExpression (Michelson.Typed.Aliases.Value t)
+ Morley.Micheline.Class: instance Morley.Micheline.Class.FromExpression Michelson.Untyped.Aliases.Value
+ Morley.Micheline.Class: instance Morley.Micheline.Class.FromExpression Michelson.Untyped.Instr.ExpandedInstr
+ Morley.Micheline.Class: instance Morley.Micheline.Class.FromExpression Michelson.Untyped.Instr.ExpandedOp
+ Morley.Micheline.Class: instance Morley.Micheline.Class.FromExpression Michelson.Untyped.Type.T
+ Morley.Micheline.Class: instance Morley.Micheline.Class.FromExpression a => Morley.Micheline.Class.FromExpression [a]
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression Michelson.Untyped.Aliases.Contract
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression Michelson.Untyped.Aliases.Value
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression Michelson.Untyped.Instr.ExpandedInstr
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression Michelson.Untyped.Instr.ExpandedOp
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression Michelson.Untyped.Type.T
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression Morley.Micheline.Expression.Expression
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression a => Morley.Micheline.Class.ToExpression (GHC.Base.NonEmpty a)
+ Morley.Micheline.Class: instance Morley.Micheline.Class.ToExpression a => Morley.Micheline.Class.ToExpression [a]
+ Morley.Micheline.Expression: _AnnotationField :: Prism' Annotation FieldAnn
+ Morley.Micheline.Expression: _AnnotationType :: Prism' Annotation TypeAnn
+ Morley.Micheline.Expression: _AnnotationVariable :: Prism' Annotation VarAnn
+ Morley.Micheline.Expression: _ExpressionPrim :: Prism' Expression MichelinePrimAp
+ Morley.Micheline.Expression: isAnnotationField :: Annotation -> Bool
+ Morley.Micheline.Expression: isAnnotationType :: Annotation -> Bool
+ Morley.Micheline.Expression: isAnnotationVariable :: Annotation -> Bool
+ Morley.Micheline.Expression: isNoAnn :: Annotation -> Bool
+ Morley.Micheline.Expression: mkAnns :: [TypeAnn] -> [FieldAnn] -> [VarAnn] -> [Annotation]
+ Morley.Micheline.Expression: mpaAnnotsL :: Lens' MichelinePrimAp [Annotation]
+ Morley.Micheline.Expression: pattern PrimExpr :: Text -> [Expression] -> [Annotation] -> Expression
+ Morley.Micheline.Expression: toAnnSet :: [Annotation] -> AnnotationSet
+ Tezos.Address: instance (TypeError ...) => Data.String.IsString Tezos.Address.Address
+ Tezos.Address: instance Language.Haskell.TH.Syntax.Lift Tezos.Address.Address
+ Tezos.Address: instance Language.Haskell.TH.Syntax.Lift Tezos.Address.ContractHash
+ Tezos.Address: instance Michelson.Printer.Util.RenderDoc Tezos.Address.ParseAddressError
+ Tezos.Address: instance Michelson.Printer.Util.RenderDoc Tezos.Address.ParseAddressRawError
+ Tezos.Address: instance Michelson.Printer.Util.RenderDoc Tezos.Address.ParseContractAddressError
+ Tezos.Address: ta :: QuasiQuoter
+ Tezos.Core: UnsafeChainId :: ByteString -> ChainId
+ Tezos.Core: UnsafeMutez :: Word64 -> Mutez
+ Tezos.Core: [unMutez] :: Mutez -> Word64
+ Tezos.Core: newtype Mutez
+ Tezos.Core: unsafeMkChainId :: HasCallStack => ByteString -> ChainId
+ Tezos.Crypto: instance Language.Haskell.TH.Syntax.Lift Tezos.Crypto.KeyHash
+ Tezos.Crypto: instance Language.Haskell.TH.Syntax.Lift Tezos.Crypto.KeyHashTag
+ Tezos.Crypto: unsafeParseKeyHash :: HasCallStack => Text -> KeyHash
+ Tezos.Crypto.BLS12381: instance Michelson.Printer.Util.RenderDoc Tezos.Crypto.BLS12381.DeserializationError
+ Tezos.Crypto.BLS12381: unsafeFromMichelsonBytes :: (CurveObject a, HasCallStack) => ByteString -> a
+ Tezos.Crypto.BLS12381: unsafeReadFromHex :: (CurveObject a, HasCallStack) => String -> a
+ Tezos.Crypto.Util: instance Michelson.Printer.Util.RenderDoc Tezos.Crypto.Util.CryptoParseError
+ Util.CLI: instance Util.CLI.HasCLReader GHC.Int.Int16
+ Util.CLI: instance Util.CLI.HasCLReader GHC.Int.Int32
+ Util.CLI: instance Util.CLI.HasCLReader GHC.Int.Int64
+ Util.CLI: instance Util.CLI.HasCLReader GHC.Int.Int8
+ Util.CLI: instance Util.CLI.HasCLReader GHC.Types.Word
+ Util.CLI: instance Util.CLI.HasCLReader GHC.Word.Word32
+ Util.CLI: instance Util.CLI.HasCLReader GHC.Word.Word8
+ Util.CLI: integralReader :: Integral a => ReadM a
+ Util.CLI: mkCommandParser :: String -> Parser a -> String -> Mod CommandFields a
+ Util.Peano: instance Data.Singletons.Internal.SingI n => Data.Singletons.Internal.SingI ('Data.Vinyl.TypeLevel.S n)
+ Util.PeanoNatural: data PeanoNatural (n :: Nat)
+ Util.PeanoNatural: fromPeanoNatural :: forall n. PeanoNatural n -> Natural
+ Util.PeanoNatural: instance Control.DeepSeq.NFData (Util.PeanoNatural.PeanoNatural n)
+ Util.PeanoNatural: instance GHC.Classes.Eq (Util.PeanoNatural.PeanoNatural n)
+ Util.PeanoNatural: instance GHC.Show.Show (Util.PeanoNatural.PeanoNatural n)
+ Util.PeanoNatural: pattern Two :: () => n ~ 'S ('S 'Z) => PeanoNatural n
+ Util.PeanoNatural: singPeanoVal :: forall (n :: Nat). SingNat n -> Natural
+ Util.PeanoNatural: toPeanoNatural :: forall n. SingI n => PeanoNatural n
+ Util.PeanoNatural: toPeanoNatural' :: forall (n :: Nat). SingI (ToPeano n) => PeanoNatural (ToPeano n)
+ Util.Positive: UnsafePositive :: Natural -> Positive
+ Util.Sing: castSing :: forall a b t. (SingI a, SingI b, SDecide (KindOf a)) => t a -> Maybe (t b)
+ Util.Sing: class SingI1 f
+ Util.Sing: eqI :: forall a b. (SingI a, SingI b, TestEquality (Sing @(KindOf a))) => Maybe (a :~: b)
+ Util.Sing: eqParamSing :: forall a1 a2 t. (SingI a1, SingI a2, SDecide (KindOf a1), Eq (t a1)) => t a1 -> t a2 -> Bool
+ Util.Sing: eqParamSing2 :: forall a1 a2 b1 b2 t. (SingI a1, SingI a2, SingI b1, SingI b2, SDecide (KindOf a1), SDecide (KindOf b1), Eq (t a1 b2)) => t a1 b1 -> t a2 b2 -> Bool
+ Util.Sing: eqParamSing3 :: forall instr1 instr2 a1 a2 b1 b2 t. (Typeable instr1, Typeable instr2, SingI a1, SingI a2, SingI b1, SingI b2, SDecide (KindOf a1), SDecide (KindOf b1), Eq (t instr1 a1 b1)) => t instr1 a1 b1 -> t instr2 a2 b2 -> Bool
+ Util.Sing: withSingI1 :: forall x r. (SingI1 f, SingI x) => (SingI (f x) => r) -> r
+ Util.Type: unsafeProvideConstraint :: MockableConstraint c => Dict c
+ Util.TypeLits: type AssertTypesEqual a b (err :: ErrorMessage) = (TypeErrorUnlessHelper (a == b) err, a ~ b)
- Michelson.FailPattern: modifyTypicalFailWith :: HasCallStack => (MText -> SomeConstrainedValue ConstantScope') -> Instr inp out -> Instr inp out
+ Michelson.FailPattern: modifyTypicalFailWith :: HasCallStack => (MText -> SomeConstrainedValue ConstantScope) -> Instr inp out -> Instr inp out
- Michelson.Interpret: InterpreterState :: MorleyLogs -> RemainingSteps -> OriginationIndex -> InterpreterState
+ Michelson.Interpret: InterpreterState :: MorleyLogs -> RemainingSteps -> OriginationIndex -> BigMapCounter -> InterpreterState
- Michelson.Interpret: [MichelsonFailedWith] :: (KnownT t, ConstantScope t) => Value t -> MichelsonFailed
+ Michelson.Interpret: [MichelsonFailedWith] :: (SingI t, ConstantScope t) => Value t -> MichelsonFailed
- Michelson.Interpret: initInterpreterState :: ContractEnv -> InterpreterState
+ Michelson.Interpret: initInterpreterState :: BigMapCounter -> ContractEnv -> InterpreterState
- Michelson.Interpret: interpret :: Contract cp st -> EntrypointCallT cp arg -> Value arg -> Value st -> ContractEnv -> ContractReturn st
+ Michelson.Interpret: interpret :: Contract cp st -> EntrypointCallT cp arg -> Value arg -> Value st -> BigMapCounter -> ContractEnv -> ContractReturn st
- Michelson.Interpret: runInstrImpl :: EvalM m => InstrRunner m -> InstrRunner m
+ Michelson.Interpret: runInstrImpl :: forall m. EvalM m => InstrRunner m -> InstrRunner m
- Michelson.Interpret.Unpack: unpackValue' :: UnpackedValScope t => ByteString -> Either UnpackError (Value t)
+ Michelson.Interpret.Unpack: unpackValue' :: forall t. UnpackedValScope t => ByteString -> Either UnpackError (Value t)
- Michelson.Macro: UF :: (VarAnn, FieldAnn) -> UnpairStruct
+ Michelson.Macro: UF :: UnpairStruct
- Michelson.Runtime: EEIllTypedParameter :: TCError -> ExecutorError' a
+ Michelson.Runtime: EEIllTypedParameter :: a -> TCError -> ExecutorError' a
- Michelson.Runtime: EEUnexpectedParameterType :: T -> T -> ExecutorError' a
+ Michelson.Runtime: EEUnexpectedParameterType :: a -> T -> T -> ExecutorError' a
- Michelson.Runtime: executeGlobalOperations :: [ExecutorOp] -> ExecutorM ()
+ Michelson.Runtime: executeGlobalOperations :: TypeCheckOptions -> [ExecutorOp] -> ExecutorM ()
- Michelson.Runtime: executeTransfer :: ("isGlobalOp" :! Bool) -> Address -> TxData -> ExecutorM [ExecutorOp]
+ Michelson.Runtime: executeTransfer :: ("isGlobalOp" :! Bool) -> TypeCheckOptions -> Address -> TxData -> ExecutorM [ExecutorOp]
- Michelson.Runtime: originateContract :: FilePath -> Address -> Maybe KeyHash -> Mutez -> Value -> Contract -> ("verbose" :! Bool) -> IO Address
+ Michelson.Runtime: originateContract :: FilePath -> TypeCheckOptions -> Address -> Maybe KeyHash -> Mutez -> Value -> Contract -> ("verbose" :! Bool) -> IO Address
- Michelson.Runtime: runContract :: Maybe Timestamp -> Maybe Natural -> Word64 -> Mutez -> FilePath -> Value -> Contract -> TxData -> ("verbose" :! Bool) -> ("dryRun" :! Bool) -> IO Value
+ Michelson.Runtime: runContract :: Maybe Timestamp -> Maybe Natural -> Word64 -> Mutez -> FilePath -> TypeCheckOptions -> Value -> Contract -> TxData -> ("verbose" :! Bool) -> ("dryRun" :! Bool) -> IO SomeStorage
- Michelson.Runtime: transfer :: Maybe Timestamp -> Maybe Natural -> Word64 -> FilePath -> Address -> TxData -> ("verbose" :! Bool) -> ("dryRun" :? Bool) -> IO ()
+ Michelson.Runtime: transfer :: Maybe Timestamp -> Maybe Natural -> Word64 -> FilePath -> TypeCheckOptions -> Address -> TxData -> ("verbose" :! Bool) -> ("dryRun" :? Bool) -> IO ()
- Michelson.Runtime.GState: GState :: ChainId -> Map Address AddressState -> VotingPowers -> GlobalCounter -> GState
+ Michelson.Runtime.GState: GState :: ChainId -> Map Address AddressState -> VotingPowers -> GlobalCounter -> BigMapCounter -> GState
- Michelson.TypeCheck: eqType :: forall (a :: T) (b :: T). Each '[KnownT] [a, b] => Either TCTypeError (a :~: b)
+ Michelson.TypeCheck: eqType :: forall (a :: T) (b :: T). Each '[SingI] [a, b] => Either TCTypeError (a :~: b)
- Michelson.TypeCheck: matchTypes :: forall t1 t2. Each '[KnownT] [t1, t2] => Notes t1 -> Notes t2 -> Either TCTypeError (t1 :~: t2, Notes t1)
+ Michelson.TypeCheck: matchTypes :: forall t1 t2. Each '[SingI] [t1, t2] => Notes t1 -> Notes t2 -> Either TCTypeError (t1 :~: t2, Notes t1)
- Michelson.TypeCheck: typeCheckContract :: Contract -> TypeCheckOptions -> Either TCError SomeContract
+ Michelson.TypeCheck: typeCheckContract :: Contract -> TypeCheckResult SomeContract
- Michelson.TypeCheck: typeCheckContractAndStorage :: Contract -> Value -> Either TCError SomeContractAndStorage
+ Michelson.TypeCheck: typeCheckContractAndStorage :: Contract -> Value -> TypeCheckResult SomeContractAndStorage
- Michelson.TypeCheck: typeCheckExt :: forall s. Typeable s => TcInstrHandler -> ExpandedExtInstr -> HST s -> TypeCheckInstrNoExcept (TypeCheckedSeq s)
+ Michelson.TypeCheck: typeCheckExt :: forall s. SingI s => TcInstrHandler -> ExpandedExtInstr -> HST s -> TypeCheckInstrNoExcept (TypeCheckedSeq s)
- Michelson.TypeCheck: typeCheckList :: Typeable inp => [ExpandedOp] -> HST inp -> TypeCheck (SomeInstr inp)
+ Michelson.TypeCheck: typeCheckList :: SingI inp => [ExpandedOp] -> HST inp -> TypeCheck (SomeInstr inp)
- Michelson.TypeCheck: typeCheckListNoExcept :: Typeable inp => [ExpandedOp] -> HST inp -> TypeCheckNoExcept (TypeCheckedSeq inp)
+ Michelson.TypeCheck: typeCheckListNoExcept :: SingI inp => [ExpandedOp] -> HST inp -> TypeCheckNoExcept (TypeCheckedSeq inp)
- Michelson.TypeCheck: typeCheckParameter :: TcOriginatedContracts -> Ty -> Value -> Either TCError SomeValue
+ Michelson.TypeCheck: typeCheckParameter :: TcOriginatedContracts -> Ty -> Value -> TypeCheckResult SomeValue
- Michelson.TypeCheck: typeCheckStorage :: Ty -> Value -> Either TCError SomeValue
+ Michelson.TypeCheck: typeCheckStorage :: Ty -> Value -> TypeCheckResult SomeValue
- Michelson.TypeCheck: typeVerifyParameter :: SingI t => TcOriginatedContracts -> Value -> Either TCError (Value t)
+ Michelson.TypeCheck: typeVerifyParameter :: SingI t => TcOriginatedContracts -> Value -> TypeCheckResult (Value t)
- Michelson.TypeCheck: typeVerifyStorage :: SingI t => Value -> Either TCError (Value t)
+ Michelson.TypeCheck: typeVerifyStorage :: SingI t => Value -> TypeCheckResult (Value t)
- Michelson.TypeCheck.Ext: typeCheckExt :: forall s. Typeable s => TcInstrHandler -> ExpandedExtInstr -> HST s -> TypeCheckInstrNoExcept (TypeCheckedSeq s)
+ Michelson.TypeCheck.Ext: typeCheckExt :: forall s. SingI s => TcInstrHandler -> ExpandedExtInstr -> HST s -> TypeCheckInstrNoExcept (TypeCheckedSeq s)
- Michelson.TypeCheck.Helpers: addImpl :: forall a b inp rs m. (Typeable rs, Each '[KnownT] [a, b], inp ~ (a : (b : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: addImpl :: forall a b inp rs m. (Each '[SingI] [a, b], inp ~ (a : (b : rs)), SingI rs, MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: arithImpl :: forall aop inp m n s t. (ArithOp aop n m, Typeable (ArithRes aop n m : s), WellTyped (ArithRes aop n m), inp ~ (n : (m : s)), MonadReader InstrCallStack t, MonadError TCError t) => Instr inp (ArithRes aop n m : s) -> HST inp -> VarAnn -> ExpandedInstr -> t (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: arithImpl :: forall aop inp m n s t. (ArithOp aop n m, WellTyped (ArithRes aop n m), inp ~ (n : (m : s)), MonadReader InstrCallStack t, MonadError TCError t) => Instr inp (ArithRes aop n m : s) -> HST inp -> VarAnn -> ExpandedInstr -> t (SomeInstr inp)
- Michelson.TypeCheck.Helpers: edivImpl :: forall a b inp rs m. (Typeable rs, Each '[KnownT] [a, b], inp ~ (a : (b : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: edivImpl :: forall a b inp rs m. (SingI rs, Each '[SingI] [a, b], inp ~ (a : (b : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: eqHST :: forall as bs. (Typeable as, Typeable bs) => HST as -> HST bs -> Either TCTypeError (as :~: bs)
+ Michelson.TypeCheck.Helpers: eqHST :: forall as bs. (SingI as, SingI bs) => HST as -> HST bs -> Either TCTypeError (as :~: bs)
- Michelson.TypeCheck.Helpers: eqHST1 :: forall t st. (Typeable st, WellTyped t) => HST st -> Either TCTypeError (st :~: '[t])
+ Michelson.TypeCheck.Helpers: eqHST1 :: forall t st. (SingI st, WellTyped t) => HST st -> Either TCTypeError (st :~: '[t])
- Michelson.TypeCheck.Helpers: eqType :: forall (a :: T) (b :: T). Each '[KnownT] [a, b] => Either TCTypeError (a :~: b)
+ Michelson.TypeCheck.Helpers: eqType :: forall (a :: T) (b :: T). Each '[SingI] [a, b] => Either TCTypeError (a :~: b)
- Michelson.TypeCheck.Helpers: getImpl :: forall c getKey rs inp m. (GetOp c, KnownT (GetOpKey c), WellTyped (GetOpVal c), inp ~ (getKey : (c : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Notes (GetOpKey c) -> HST inp -> Notes (GetOpVal c) -> VarAnn -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: getImpl :: forall c getKey rs inp m. (GetOp c, SingI (GetOpKey c), WellTyped (GetOpVal c), inp ~ (getKey : (c : rs)), SingI rs, MonadReader InstrCallStack m, MonadError TCError m) => Notes (GetOpKey c) -> HST inp -> Notes (GetOpVal c) -> VarAnn -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: getUpdImpl :: forall c updKey updParams rs inp m. (UpdOp c, GetOp c, KnownT (UpdOpKey c), KnownT (GetOpVal c), inp ~ (updKey : (updParams : (c : rs))), GetOpKey c ~ UpdOpKey c, UpdOpParams c ~ 'TOption (GetOpVal c), MonadReader InstrCallStack m, MonadError TCError m) => Notes (UpdOpKey c) -> HST inp -> Notes (UpdOpParams c) -> VarAnn -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: getUpdImpl :: forall c updKey updParams rs inp m. (UpdOp c, GetOp c, SingI (UpdOpKey c), SingI (GetOpVal c), inp ~ (updKey : (updParams : (c : rs))), SingI rs, GetOpKey c ~ UpdOpKey c, UpdOpParams c ~ 'TOption (GetOpVal c), MonadReader InstrCallStack m, MonadError TCError m) => Notes (UpdOpKey c) -> HST inp -> Notes (UpdOpParams c) -> VarAnn -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: matchTypes :: forall t1 t2. Each '[KnownT] [t1, t2] => Notes t1 -> Notes t2 -> Either TCTypeError (t1 :~: t2, Notes t1)
+ Michelson.TypeCheck.Helpers: matchTypes :: forall t1 t2. Each '[SingI] [t1, t2] => Notes t1 -> Notes t2 -> Either TCTypeError (t1 :~: t2, Notes t1)
- Michelson.TypeCheck.Helpers: memImpl :: forall c memKey rs inp m. (MemOp c, KnownT (MemOpKey c), inp ~ (memKey : (c : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Notes (MemOpKey c) -> HST inp -> VarAnn -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: memImpl :: forall c memKey rs inp m. (MemOp c, SingI (MemOpKey c), inp ~ (memKey : (c : rs)), SingI rs, MonadReader InstrCallStack m, MonadError TCError m) => Notes (MemOpKey c) -> HST inp -> VarAnn -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: mulImpl :: forall a b inp rs m. (Typeable rs, Each '[KnownT] [a, b], inp ~ (a : (b : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: mulImpl :: forall a b inp rs m. (Each '[SingI] [a, b], inp ~ (a : (b : rs)), SingI rs, MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: onTypeCheckInstrAnnErr :: (MonadReader InstrCallStack m, MonadError TCError m, Typeable ts) => ExpandedInstr -> HST ts -> Maybe TypeContext -> Either AnnConvergeError a -> m a
+ Michelson.TypeCheck.Helpers: onTypeCheckInstrAnnErr :: (MonadReader InstrCallStack m, MonadError TCError m, SingI ts) => ExpandedInstr -> HST ts -> Maybe TypeContext -> Either AnnConvergeError a -> m a
- Michelson.TypeCheck.Helpers: sliceImpl :: (SliceOp c, Typeable c, inp ~ ('TNat : ('TNat : (c : rs))), Monad m) => HST inp -> VarAnn -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: sliceImpl :: (SliceOp c, inp ~ ('TNat : ('TNat : (c : rs))), Monad m) => HST inp -> VarAnn -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: subImpl :: forall a b inp rs m. (Typeable rs, Each '[KnownT] [a, b], inp ~ (a : (b : rs)), MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: subImpl :: forall a b inp rs m. (Each '[SingI] [a, b], inp ~ (a : (b : rs)), SingI rs, MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Sing b -> HST inp -> VarAnn -> ExpandedInstr -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: typeCheckImpl :: forall inp. Typeable inp => TcInstrHandler -> [ExpandedOp] -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
+ Michelson.TypeCheck.Helpers: typeCheckImpl :: forall inp. SingI inp => TcInstrHandler -> [ExpandedOp] -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
- Michelson.TypeCheck.Helpers: typeCheckImplStripped :: forall inp. Typeable inp => TcInstrHandler -> [ExpandedOp] -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
+ Michelson.TypeCheck.Helpers: typeCheckImplStripped :: forall inp. SingI inp => TcInstrHandler -> [ExpandedOp] -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
- Michelson.TypeCheck.Helpers: unaryArithImpl :: (Typeable (UnaryArithRes aop n : s), WellTyped (UnaryArithRes aop n), inp ~ (n : s), Monad t) => Instr inp (UnaryArithRes aop n : s) -> HST inp -> VarAnn -> t (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: unaryArithImpl :: (WellTyped (UnaryArithRes aop n), inp ~ (n : s), Monad t) => Instr inp (UnaryArithRes aop n : s) -> HST inp -> VarAnn -> t (SomeInstr inp)
- Michelson.TypeCheck.Helpers: unaryArithImplAnnotated :: (Typeable (UnaryArithRes aop n : s), WellTyped (UnaryArithRes aop n), inp ~ (n : s), Monad t, n ~ UnaryArithRes aop n) => Instr inp (UnaryArithRes aop n : s) -> HST inp -> VarAnn -> t (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: unaryArithImplAnnotated :: (WellTyped (UnaryArithRes aop n), inp ~ (n : s), Monad t, n ~ UnaryArithRes aop n) => Instr inp (UnaryArithRes aop n : s) -> HST inp -> VarAnn -> t (SomeInstr inp)
- Michelson.TypeCheck.Helpers: updImpl :: forall c updKey updParams rs inp m. (UpdOp c, KnownT (UpdOpKey c), KnownT (UpdOpParams c), inp ~ (updKey : (updParams : (c : rs))), MonadReader InstrCallStack m, MonadError TCError m) => Notes (UpdOpKey c) -> HST inp -> Notes (UpdOpParams c) -> VarAnn -> m (SomeInstr inp)
+ Michelson.TypeCheck.Helpers: updImpl :: forall c updKey updParams rs inp m. (UpdOp c, SingI (UpdOpKey c), SingI (UpdOpParams c), SingI rs, inp ~ (updKey : (updParams : (c : rs))), MonadReader InstrCallStack m, MonadError TCError m) => Notes (UpdOpKey c) -> HST inp -> Notes (UpdOpParams c) -> VarAnn -> m (SomeInstr inp)
- Michelson.TypeCheck.Helpers: withCompareableCheck :: forall a m v ts. (Typeable ts, MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> ExpandedInstr -> HST ts -> (Comparable a => v) -> m v
+ Michelson.TypeCheck.Helpers: withCompareableCheck :: forall a m v ts. (SingI ts, MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> ExpandedInstr -> HST ts -> (Comparable a => v) -> m v
- Michelson.TypeCheck.Instr: typeCheckContract :: Contract -> TypeCheckOptions -> Either TCError SomeContract
+ Michelson.TypeCheck.Instr: typeCheckContract :: Contract -> TypeCheckResult SomeContract
- Michelson.TypeCheck.Instr: typeCheckContractAndStorage :: Contract -> Value -> Either TCError SomeContractAndStorage
+ Michelson.TypeCheck.Instr: typeCheckContractAndStorage :: Contract -> Value -> TypeCheckResult SomeContractAndStorage
- Michelson.TypeCheck.Instr: typeCheckList :: Typeable inp => [ExpandedOp] -> HST inp -> TypeCheck (SomeInstr inp)
+ Michelson.TypeCheck.Instr: typeCheckList :: SingI inp => [ExpandedOp] -> HST inp -> TypeCheck (SomeInstr inp)
- Michelson.TypeCheck.Instr: typeCheckListNoExcept :: Typeable inp => [ExpandedOp] -> HST inp -> TypeCheckNoExcept (TypeCheckedSeq inp)
+ Michelson.TypeCheck.Instr: typeCheckListNoExcept :: SingI inp => [ExpandedOp] -> HST inp -> TypeCheckNoExcept (TypeCheckedSeq inp)
- Michelson.TypeCheck.Instr: typeCheckParameter :: TcOriginatedContracts -> Ty -> Value -> Either TCError SomeValue
+ Michelson.TypeCheck.Instr: typeCheckParameter :: TcOriginatedContracts -> Ty -> Value -> TypeCheckResult SomeValue
- Michelson.TypeCheck.Instr: typeCheckStorage :: Ty -> Value -> Either TCError SomeValue
+ Michelson.TypeCheck.Instr: typeCheckStorage :: Ty -> Value -> TypeCheckResult SomeValue
- Michelson.TypeCheck.Instr: typeVerifyParameter :: SingI t => TcOriginatedContracts -> Value -> Either TCError (Value t)
+ Michelson.TypeCheck.Instr: typeVerifyParameter :: SingI t => TcOriginatedContracts -> Value -> TypeCheckResult (Value t)
- Michelson.TypeCheck.Instr: typeVerifyStorage :: SingI t => Value -> Either TCError (Value t)
+ Michelson.TypeCheck.Instr: typeVerifyStorage :: SingI t => Value -> TypeCheckResult (Value t)
- Michelson.TypeCheck.TypeCheck: TypeCheckOptions :: Bool -> TypeCheckOptions
+ Michelson.TypeCheck.TypeCheck: TypeCheckOptions :: Bool -> Bool -> TypeCheckOptions
- Michelson.TypeCheck.TypeCheck: runTypeCheck :: TypeCheckMode -> TypeCheckOptions -> TypeCheck a -> Either TCError a
+ Michelson.TypeCheck.TypeCheck: runTypeCheck :: TypeCheckMode -> TypeCheck a -> TypeCheckResult a
- Michelson.TypeCheck.TypeCheck: runTypeCheckInstrIsolated :: TypeCheckInstr a -> Either TCError a
+ Michelson.TypeCheck.TypeCheck: runTypeCheckInstrIsolated :: TypeCheckInstr a -> TypeCheckResult a
- Michelson.TypeCheck.TypeCheck: runTypeCheckIsolated :: TypeCheck a -> Either TCError a
+ Michelson.TypeCheck.TypeCheck: runTypeCheckIsolated :: TypeCheck a -> TypeCheckResult a
- Michelson.TypeCheck.TypeCheck: type TcInstrHandler = forall inp. (Typeable inp, HasCallStack) => ExpandedInstr -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
+ Michelson.TypeCheck.TypeCheck: type TcInstrHandler = forall inp. (SingI inp, HasCallStack) => ExpandedInstr -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
- Michelson.TypeCheck.TypeCheckedOp: [WellTypedOp] :: (Typeable inp, Typeable out) => Instr inp out -> TypeCheckedOp
+ Michelson.TypeCheck.TypeCheckedOp: [WellTypedOp] :: (SingI inp, SingI out) => Instr inp out -> TypeCheckedOp
- Michelson.TypeCheck.TypeCheckedSeq: [WellTypedOp] :: (Typeable inp, Typeable out) => Instr inp out -> TypeCheckedOp
+ Michelson.TypeCheck.TypeCheckedSeq: [WellTypedOp] :: (SingI inp, SingI out) => Instr inp out -> TypeCheckedOp
- Michelson.TypeCheck.Types: (-:&) :: (Typeable xs, WellTyped x) => Sing x -> HST xs -> HST (x : xs)
+ Michelson.TypeCheck.Types: (-:&) :: (WellTyped x, SingI xs) => Sing x -> HST xs -> HST (x : xs)
- Michelson.TypeCheck.Types: NotWellTyped :: T -> NotWellTyped
+ Michelson.TypeCheck.Types: NotWellTyped :: T -> BadTypeForScope -> NotWellTyped
- Michelson.TypeCheck.Types: [::&] :: (Typeable xs, KnownT x) => (Notes x, Dict (WellTyped x), VarAnn) -> HST xs -> HST (x : xs)
+ Michelson.TypeCheck.Types: [::&] :: (SingI x, SingI xs) => (Notes x, Dict (WellTyped x), VarAnn) -> HST xs -> HST (x : xs)
- Michelson.TypeCheck.Types: [:::] :: Typeable out => Instr inp out -> HST out -> SomeInstrOut inp
+ Michelson.TypeCheck.Types: [:::] :: SingI out => Instr inp out -> HST out -> SomeInstrOut inp
- Michelson.TypeCheck.Types: [SomeHST] :: Typeable ts => HST ts -> SomeHST
+ Michelson.TypeCheck.Types: [SomeHST] :: SingI ts => HST ts -> SomeHST
- Michelson.TypeCheck.Types: pattern (::&+) :: () => (ys ~ (x : xs), KnownT x, Typeable xs) => (Sing x, Notes x, Dict (WellTyped x), VarAnn) -> HST xs -> HST ys
+ Michelson.TypeCheck.Types: pattern (::&+) :: () => (ys ~ (x : xs), SingI x, SingI xs) => (Sing x, Notes x, Dict (WellTyped x), VarAnn) -> HST xs -> HST ys
- Michelson.Typed.Convert: convertContract :: forall param store. (SingI param, SingI store) => Contract param store -> Contract
+ Michelson.Typed.Convert: convertContract :: Contract param store -> Contract
- Michelson.Typed.Convert: untypeValue :: forall t. (SingI t, HasNoOp t) => Value' Instr t -> Value
+ Michelson.Typed.Convert: untypeValue :: (SingI t, HasNoOp t) => Value' Instr t -> Value
- Michelson.Typed.Entrypoints: [EplWrapLeft] :: (KnownT subparam, KnownT r) => EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr subparam r)
+ Michelson.Typed.Entrypoints: [EplWrapLeft] :: (SingI subparam, SingI r) => EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr subparam r)
- Michelson.Typed.Entrypoints: [EplWrapRight] :: (KnownT l, KnownT subparam) => EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr l subparam)
+ Michelson.Typed.Entrypoints: [EplWrapRight] :: (SingI l, SingI subparam) => EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr l subparam)
- Michelson.Typed.Extract: pattern AsUType :: () => KnownT t => Notes t -> Ty
+ Michelson.Typed.Extract: pattern AsUType :: () => SingI t => Notes t -> Ty
- Michelson.Typed.Extract: pattern AsUTypeExt :: () => KnownT t => Sing t -> Notes t -> Ty
+ Michelson.Typed.Extract: pattern AsUTypeExt :: () => SingI t => Sing t -> Notes t -> Ty
- Michelson.Typed.Extract: withUType :: Ty -> (forall t. KnownT t => Notes t -> r) -> r
+ Michelson.Typed.Extract: withUType :: Ty -> (forall t. SingI t => Notes t -> r) -> r
- Michelson.Typed.Haskell: BigMap :: Map k v -> BigMap k v
+ Michelson.Typed.Haskell: BigMap :: Maybe (BigMapId k v) -> Map k v -> BigMap k v
- Michelson.Typed.Haskell: ComposeFieldTypeMismatch :: TypeRep -> TypeRep -> ComposeResult a
+ Michelson.Typed.Haskell: ComposeFieldTypeMismatch :: T -> T -> ComposeResult a
- Michelson.Typed.Haskell: class (KnownT t, WellTypedSuperC t) => WellTyped (t :: T)
+ Michelson.Typed.Haskell: class (SingI t, WellTypedSuperC t) => WellTyped (t :: T)
- Michelson.Typed.Haskell: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, KnownIsoT a, HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
- Michelson.Typed.Haskell: crDescriptionL :: forall a_a5NXy. Lens' (ConstructorRep a_a5NXy) (Maybe Text)
+ Michelson.Typed.Haskell: crDescriptionL :: forall a_a6iMb. Lens' (ConstructorRep a_a6iMb) (Maybe Text)
- Michelson.Typed.Haskell: crFieldsL :: forall a_a5NXy a_a5NYK. Lens (ConstructorRep a_a5NXy) (ConstructorRep a_a5NYK) [FieldRep a_a5NXy] [FieldRep a_a5NYK]
+ Michelson.Typed.Haskell: crFieldsL :: forall a_a6iMb a_a6iNn. Lens (ConstructorRep a_a6iMb) (ConstructorRep a_a6iNn) [FieldRep a_a6iMb] [FieldRep a_a6iNn]
- Michelson.Typed.Haskell: crNameL :: forall a_a5NXy. Lens' (ConstructorRep a_a5NXy) Text
+ Michelson.Typed.Haskell: crNameL :: forall a_a6iMb. Lens' (ConstructorRep a_a6iMb) Text
- Michelson.Typed.Haskell: frDescriptionL :: forall a_a5NXx. Lens' (FieldRep a_a5NXx) (Maybe Text)
+ Michelson.Typed.Haskell: frDescriptionL :: forall a_a6iMa. Lens' (FieldRep a_a6iMa) (Maybe Text)
- Michelson.Typed.Haskell: frNameL :: forall a_a5NXx. Lens' (FieldRep a_a5NXx) (Maybe Text)
+ Michelson.Typed.Haskell: frNameL :: forall a_a6iMa. Lens' (FieldRep a_a6iMa) (Maybe Text)
- Michelson.Typed.Haskell: frTypeRepL :: forall a_a5NXx a_a5O0s. Lens (FieldRep a_a5NXx) (FieldRep a_a5O0s) a_a5NXx a_a5O0s
+ Michelson.Typed.Haskell: frTypeRepL :: forall a_a6iMa a_a6iP5. Lens (FieldRep a_a6iMa) (FieldRep a_a6iP5) a_a6iMa a_a6iP5
- Michelson.Typed.Haskell: homomorphicTypeDocMichelsonRep :: forall a. SingI (ToT a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell: homomorphicTypeDocMichelsonRep :: forall a. KnownIsoT a => TypeDocMichelsonRep a
- Michelson.Typed.Haskell: type KnownIsoT a = KnownT (ToT a)
+ Michelson.Typed.Haskell: type KnownIsoT a = SingI (ToT a)
- Michelson.Typed.Haskell: typeDocMichelsonRep :: (TypeHasDoc a, SingI (ToT a), IsHomomorphic a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell: typeDocMichelsonRep :: (TypeHasDoc a, KnownIsoT a, IsHomomorphic a) => TypeDocMichelsonRep a
- Michelson.Typed.Haskell.Doc: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
+ Michelson.Typed.Haskell.Doc: concreteTypeDocMichelsonRep :: forall a b. (Typeable a, KnownIsoT a, HaveCommonTypeCtor b a) => TypeDocMichelsonRep b
- Michelson.Typed.Haskell.Doc: crDescriptionL :: forall a_a5NXy. Lens' (ConstructorRep a_a5NXy) (Maybe Text)
+ Michelson.Typed.Haskell.Doc: crDescriptionL :: forall a_a6iMb. Lens' (ConstructorRep a_a6iMb) (Maybe Text)
- Michelson.Typed.Haskell.Doc: crFieldsL :: forall a_a5NXy a_a5NYK. Lens (ConstructorRep a_a5NXy) (ConstructorRep a_a5NYK) [FieldRep a_a5NXy] [FieldRep a_a5NYK]
+ Michelson.Typed.Haskell.Doc: crFieldsL :: forall a_a6iMb a_a6iNn. Lens (ConstructorRep a_a6iMb) (ConstructorRep a_a6iNn) [FieldRep a_a6iMb] [FieldRep a_a6iNn]
- Michelson.Typed.Haskell.Doc: crNameL :: forall a_a5NXy. Lens' (ConstructorRep a_a5NXy) Text
+ Michelson.Typed.Haskell.Doc: crNameL :: forall a_a6iMb. Lens' (ConstructorRep a_a6iMb) Text
- Michelson.Typed.Haskell.Doc: frDescriptionL :: forall a_a5NXx. Lens' (FieldRep a_a5NXx) (Maybe Text)
+ Michelson.Typed.Haskell.Doc: frDescriptionL :: forall a_a6iMa. Lens' (FieldRep a_a6iMa) (Maybe Text)
- Michelson.Typed.Haskell.Doc: frNameL :: forall a_a5NXx. Lens' (FieldRep a_a5NXx) (Maybe Text)
+ Michelson.Typed.Haskell.Doc: frNameL :: forall a_a6iMa. Lens' (FieldRep a_a6iMa) (Maybe Text)
- Michelson.Typed.Haskell.Doc: frTypeRepL :: forall a_a5NXx a_a5O0s. Lens (FieldRep a_a5NXx) (FieldRep a_a5O0s) a_a5NXx a_a5O0s
+ Michelson.Typed.Haskell.Doc: frTypeRepL :: forall a_a6iMa a_a6iP5. Lens (FieldRep a_a6iMa) (FieldRep a_a6iP5) a_a6iMa a_a6iP5
- Michelson.Typed.Haskell.Doc: homomorphicTypeDocMichelsonRep :: forall a. SingI (ToT a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell.Doc: homomorphicTypeDocMichelsonRep :: forall a. KnownIsoT a => TypeDocMichelsonRep a
- Michelson.Typed.Haskell.Doc: typeDocMichelsonRep :: (TypeHasDoc a, SingI (ToT a), IsHomomorphic a) => TypeDocMichelsonRep a
+ Michelson.Typed.Haskell.Doc: typeDocMichelsonRep :: (TypeHasDoc a, KnownIsoT a, IsHomomorphic a) => TypeDocMichelsonRep a
- Michelson.Typed.Haskell.LooseSum: ComposeFieldTypeMismatch :: TypeRep -> TypeRep -> ComposeResult a
+ Michelson.Typed.Haskell.LooseSum: ComposeFieldTypeMismatch :: T -> T -> ComposeResult a
- Michelson.Typed.Haskell.Value: BigMap :: Map k v -> BigMap k v
+ Michelson.Typed.Haskell.Value: BigMap :: Maybe (BigMapId k v) -> Map k v -> BigMap k v
- Michelson.Typed.Haskell.Value: class KnownT (GValueType x) => GIsoValue (x :: Type -> Type) where {
+ Michelson.Typed.Haskell.Value: class SingI (GValueType x) => GIsoValue (x :: Type -> Type) where {
- Michelson.Typed.Haskell.Value: class (KnownT t, WellTypedSuperC t) => WellTyped (t :: T)
+ Michelson.Typed.Haskell.Value: class (SingI t, WellTypedSuperC t) => WellTyped (t :: T)
- Michelson.Typed.Haskell.Value: type KnownIsoT a = KnownT (ToT a)
+ Michelson.Typed.Haskell.Value: type KnownIsoT a = SingI (ToT a)
- Michelson.Typed.Instr: [APPLY] :: forall a b c s. (ConstantScope a, KnownT b) => Instr (a : ('TLambda ('TPair a b) c : s)) ('TLambda b c : s)
+ Michelson.Typed.Instr: [APPLY] :: forall a b c s. (ConstantScope a, SingI b) => Instr (a : ('TLambda ('TPair a b) c : s)) ('TLambda b c : s)
- Michelson.Typed.Instr: [AnnCAR] :: FieldAnn -> Instr ('TPair a b : s) (a : s)
+ Michelson.Typed.Instr: [AnnCAR] :: VarAnn -> FieldAnn -> Instr ('TPair a b : s) (a : s)
- Michelson.Typed.Instr: [AnnCDR] :: FieldAnn -> Instr ('TPair a b : s) (b : s)
+ Michelson.Typed.Instr: [AnnCDR] :: VarAnn -> FieldAnn -> Instr ('TPair a b : s) (b : s)
- Michelson.Typed.Instr: [AnnLEFT] :: KnownT b => TypeAnn -> FieldAnn -> FieldAnn -> Instr (a : s) ('TOr a b : s)
+ Michelson.Typed.Instr: [AnnLEFT] :: SingI b => TypeAnn -> FieldAnn -> FieldAnn -> Instr (a : s) ('TOr a b : s)
- Michelson.Typed.Instr: [AnnRIGHT] :: KnownT a => TypeAnn -> FieldAnn -> FieldAnn -> Instr (b : s) ('TOr a b : s)
+ Michelson.Typed.Instr: [AnnRIGHT] :: SingI a => TypeAnn -> FieldAnn -> FieldAnn -> Instr (b : s) ('TOr a b : s)
- Michelson.Typed.Instr: [COMPARE] :: (Comparable n, KnownT n) => Instr (n : (n : s)) ('TInt : s)
+ Michelson.Typed.Instr: [COMPARE] :: (Comparable n, SingI n) => Instr (n : (n : s)) ('TInt : s)
- Michelson.Typed.Instr: [DIG] :: forall (n :: Peano) inp out a. (ConstraintDIG n inp out a, NFData (Sing n)) => Sing n -> Instr inp out
+ Michelson.Typed.Instr: [DIG] :: forall (n :: Peano) inp out a. (ConstraintDIG n inp out a, NFData (Sing n)) => PeanoNatural n -> Instr inp out
- Michelson.Typed.Instr: [DIPN] :: forall (n :: Peano) inp out s s'. (ConstraintDIPN n inp out s s', NFData (Sing n)) => Sing n -> Instr s s' -> Instr inp out
+ Michelson.Typed.Instr: [DIPN] :: forall (n :: Peano) inp out s s'. (ConstraintDIPN n inp out s s', NFData (Sing n)) => PeanoNatural n -> Instr s s' -> Instr inp out
- Michelson.Typed.Instr: [DROPN] :: forall (n :: Peano) s. (SingI n, KnownPeano n, RequireLongerOrSameLength s n, NFData (Sing n)) => Sing n -> Instr s (Drop n s)
+ Michelson.Typed.Instr: [DROPN] :: forall (n :: Peano) s. (RequireLongerOrSameLength s n, NFData (Sing n)) => PeanoNatural n -> Instr s (Drop n s)
- Michelson.Typed.Instr: [DUG] :: forall (n :: Peano) inp out a. (ConstraintDUG n inp out a, NFData (Sing n)) => Sing n -> Instr inp out
+ Michelson.Typed.Instr: [DUG] :: forall (n :: Peano) inp out a. (ConstraintDUG n inp out a, NFData (Sing n)) => PeanoNatural n -> Instr inp out
- Michelson.Typed.Instr: [DUPN] :: forall (n :: Peano) inp out a. (ConstraintDUPN n inp out a, NFData (Sing n)) => Sing n -> Instr inp out
+ Michelson.Typed.Instr: [DUPN] :: forall (n :: Peano) inp out a. (ConstraintDUPN n inp out a, DupableScope a, NFData (Sing n)) => PeanoNatural n -> Instr inp out
- Michelson.Typed.Instr: [DUP] :: Instr (a : s) (a : (a : s))
+ Michelson.Typed.Instr: [DUP] :: DupableScope a => Instr (a : s) (a : (a : s))
- Michelson.Typed.Instr: [EMPTY_BIG_MAP] :: (KnownT a, KnownT b, Comparable a) => Instr s ('TBigMap a b : s)
+ Michelson.Typed.Instr: [EMPTY_BIG_MAP] :: (SingI a, SingI b, Comparable a, HasNoBigMap b) => Instr s ('TBigMap a b : s)
- Michelson.Typed.Instr: [EMPTY_MAP] :: (KnownT a, KnownT b, Comparable a) => Instr s ('TMap a b : s)
+ Michelson.Typed.Instr: [EMPTY_MAP] :: (SingI a, SingI b, Comparable a) => Instr s ('TMap a b : s)
- Michelson.Typed.Instr: [EMPTY_SET] :: (KnownT e, Comparable e) => Instr s ('TSet e : s)
+ Michelson.Typed.Instr: [EMPTY_SET] :: (SingI e, Comparable e) => Instr s ('TSet e : s)
- Michelson.Typed.Instr: [FAILWITH] :: (KnownT a, ConstantScope a) => Instr (a : s) t
+ Michelson.Typed.Instr: [FAILWITH] :: (SingI a, ConstantScope a) => Instr (a : s) t
- Michelson.Typed.Instr: [GETN] :: forall (ix :: Peano) (pair :: T) (s :: [T]). ConstraintGetN ix pair => Sing ix -> Instr (pair : s) (GetN ix pair : s)
+ Michelson.Typed.Instr: [GETN] :: forall (ix :: Peano) (pair :: T) (s :: [T]). ConstraintGetN ix pair => PeanoNatural ix -> Instr (pair : s) (GetN ix pair : s)
- Michelson.Typed.Instr: [GET] :: (GetOp c, KnownT (GetOpVal c)) => Instr (GetOpKey c : (c : s)) ('TOption (GetOpVal c) : s)
+ Michelson.Typed.Instr: [GET] :: (GetOp c, SingI (GetOpVal c)) => Instr (GetOpKey c : (c : s)) ('TOption (GetOpVal c) : s)
- Michelson.Typed.Instr: [GET_AND_UPDATE] :: (GetOp c, UpdOp c, KnownT (GetOpVal c), UpdOpKey c ~ GetOpKey c) => Instr (UpdOpKey c : (UpdOpParams c : (c : s))) ('TOption (GetOpVal c) : (c : s))
+ Michelson.Typed.Instr: [GET_AND_UPDATE] :: (GetOp c, UpdOp c, SingI (GetOpVal c), UpdOpKey c ~ GetOpKey c) => Instr (UpdOpKey c : (UpdOpParams c : (c : s))) ('TOption (GetOpVal c) : (c : s))
- Michelson.Typed.Instr: [LAMBDA] :: forall i o s. (KnownT i, KnownT o) => Value' Instr ('TLambda i o) -> Instr s ('TLambda i o : s)
+ Michelson.Typed.Instr: [LAMBDA] :: forall i o s. (SingI i, SingI o) => Value' Instr ('TLambda i o) -> Instr s ('TLambda i o : s)
- Michelson.Typed.Instr: [MAP] :: (MapOp c, KnownT b) => Instr (MapOpInp c : s) (b : s) -> Instr (c : s) (MapOpRes c b : s)
+ Michelson.Typed.Instr: [MAP] :: (MapOp c, SingI b) => Instr (MapOpInp c : s) (b : s) -> Instr (c : s) (MapOpRes c b : s)
- Michelson.Typed.Instr: [NIL] :: KnownT p => Instr s ('TList p : s)
+ Michelson.Typed.Instr: [NIL] :: SingI p => Instr s ('TList p : s)
- Michelson.Typed.Instr: [NONE] :: forall a s. KnownT a => Instr s ('TOption a : s)
+ Michelson.Typed.Instr: [NONE] :: forall a s. SingI a => Instr s ('TOption a : s)
- Michelson.Typed.Instr: [PAIRN] :: forall n inp. ConstraintPairN n inp => Sing n -> Instr inp (PairN n inp)
+ Michelson.Typed.Instr: [PAIRN] :: forall n inp. ConstraintPairN n inp => PeanoNatural n -> Instr inp (PairN n inp)
- Michelson.Typed.Instr: [SLICE] :: (SliceOp c, KnownT c) => Instr ('TNat : ('TNat : (c : s))) ('TOption c : s)
+ Michelson.Typed.Instr: [SLICE] :: (SliceOp c, SingI c) => Instr ('TNat : ('TNat : (c : s))) ('TOption c : s)
- Michelson.Typed.Instr: [StackRef] :: (KnownPeano idx, SingI idx, RequireLongerThan st idx) => Sing (idx :: Peano) -> StackRef st
+ Michelson.Typed.Instr: [StackRef] :: RequireLongerThan st idx => PeanoNatural idx -> StackRef st
- Michelson.Typed.Instr: [TestAssert] :: Typeable out => Text -> PrintComment inp -> Instr inp ('TBool : out) -> TestAssert inp
+ Michelson.Typed.Instr: [TestAssert] :: SingI out => Text -> PrintComment inp -> Instr inp ('TBool : out) -> TestAssert inp
- Michelson.Typed.Instr: [UNPACK] :: (UnpackedValScope a, KnownT a) => Instr ('TBytes : s) ('TOption a : s)
+ Michelson.Typed.Instr: [UNPACK] :: (UnpackedValScope a, SingI a) => Instr ('TBytes : s) ('TOption a : s)
- Michelson.Typed.Instr: [UNPAIRN] :: forall (n :: Peano) (pair :: T) (s :: [T]). ConstraintUnpairN n pair => Sing n -> Instr (pair : s) (UnpairN n pair ++ s)
+ Michelson.Typed.Instr: [UNPAIRN] :: forall (n :: Peano) (pair :: T) (s :: [T]). ConstraintUnpairN n pair => PeanoNatural n -> Instr (pair : s) (UnpairN n pair ++ s)
- Michelson.Typed.Instr: [UPDATEN] :: forall (ix :: Peano) (val :: T) (pair :: T) (s :: [T]). ConstraintUpdateN ix pair => Sing ix -> Instr (val : (pair : s)) (UpdateN ix val pair : s)
+ Michelson.Typed.Instr: [UPDATEN] :: forall (ix :: Peano) (val :: T) (pair :: T) (s :: [T]). ConstraintUpdateN ix pair => PeanoNatural ix -> Instr (val : (pair : s)) (UpdateN ix val pair : s)
- Michelson.Typed.Instr: mkStackRef :: forall (gn :: Nat) st n. (n ~ ToPeano gn, SingI n, KnownPeano n, RequireLongerThan st n) => StackRef st
+ Michelson.Typed.Instr: mkStackRef :: forall (gn :: Nat) st n. (n ~ ToPeano gn, SingI (ToPeano gn), RequireLongerThan st n) => StackRef st
- Michelson.Typed.Instr: type ConstraintDIG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (SingI n, KnownPeano n, RequireLongerThan inp n, inp ~ (Take n inp ++ (a : Drop ('S n) inp)), out ~ (a : Take n inp ++ Drop ('S n) inp))
+ Michelson.Typed.Instr: type ConstraintDIG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (RequireLongerThan inp n, inp ~ (Take n inp ++ (a : Drop ('S n) inp)), out ~ (a : Take n inp ++ Drop ('S n) inp))
- Michelson.Typed.Instr: type ConstraintDIPN' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (s :: [kind]) (s' :: [kind]) = (SingI n, KnownPeano n, RequireLongerOrSameLength inp n, ((Take n inp) ++ s) ~ inp, ((Take n inp) ++ s') ~ out)
+ Michelson.Typed.Instr: type ConstraintDIPN' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (s :: [kind]) (s' :: [kind]) = (RequireLongerOrSameLength inp n, ((Take n inp) ++ s) ~ inp, ((Take n inp) ++ s') ~ out)
- Michelson.Typed.Instr: type ConstraintDUG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (SingI n, KnownPeano n, RequireLongerThan out n, inp ~ (a : Drop ('S 'Z) inp), out ~ (Take n (Drop ('S 'Z) inp) ++ (a : Drop ('S n) inp)))
+ Michelson.Typed.Instr: type ConstraintDUG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (RequireLongerThan out n, inp ~ (a : Drop ('S 'Z) inp), out ~ (Take n (Drop ('S 'Z) inp) ++ (a : Drop ('S n) inp)))
- Michelson.Typed.Instr: type ConstraintDUPN' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (SingI n, KnownPeano n, RequireLongerOrSameLength inp n, n > 'Z ~ 'True, inp ~ (Take (Decrement n) inp ++ (a : Drop n inp)), out ~ (a : inp))
+ Michelson.Typed.Instr: type ConstraintDUPN' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) = (RequireLongerOrSameLength inp n, n > 'Z ~ 'True, inp ~ (Take (Decrement n) inp ++ (a : Drop n inp)), out ~ (a : inp))
- Michelson.Typed.Instr: type ConstraintGetN (ix :: Peano) (pair :: T) = (TypeErrorUnless (CombedPairNodeIndexIsValid ix pair) (If (IsPair pair) ('Text "'GET " :<>: 'ShowType (FromPeano ix) :<>: 'Text "' expects a right-combed pair with at least " :<>: 'ShowType (FromPeano ix + 1) :<>: 'Text " nodes at the top of the stack," :$$: 'Text "but the pair only contains " :<>: 'ShowType (FromPeano (CombedPairNodeCount pair)) :<>: 'Text " nodes.") ('Text "Expected a pair at the top of the stack, but found: " :<>: 'ShowType pair)), SingI ix, KnownPeano ix)
+ Michelson.Typed.Instr: type ConstraintGetN (ix :: Peano) (pair :: T) = (TypeErrorUnless (CombedPairNodeIndexIsValid ix pair) (If (IsPair pair) ('Text "'GET " :<>: 'ShowType (FromPeano ix) :<>: 'Text "' expects a right-combed pair with at least " :<>: 'ShowType (FromPeano ix + 1) :<>: 'Text " nodes at the top of the stack," :$$: 'Text "but the pair only contains " :<>: 'ShowType (FromPeano (CombedPairNodeCount pair)) :<>: 'Text " nodes.") ('Text "Expected a pair at the top of the stack, but found: " :<>: 'ShowType pair)))
- Michelson.Typed.Instr: type ConstraintPairN (n :: Peano) (inp :: [T]) = (RequireLongerOrSameLength inp n, TypeErrorUnless (n >= ToPeano 2) ('Text "'PAIR n' expects n \8805 2"), SingI n, KnownPeano n)
+ Michelson.Typed.Instr: type ConstraintPairN (n :: Peano) (inp :: [T]) = (RequireLongerOrSameLength inp n, TypeErrorUnless (n >= ToPeano 2) ('Text "'PAIR n' expects n \8805 2"))
- Michelson.Typed.Instr: type ConstraintUnpairN (n :: Peano) (pair :: T) = (TypeErrorUnless (n >= ToPeano 2) ('Text "'UNPAIR n' expects n \8805 2"), TypeErrorUnless (CombedPairLeafCountIsAtLeast n pair) (If (IsPair pair) ('Text "'UNPAIR " :<>: 'ShowType (FromPeano n) :<>: 'Text "' expects a right-combed pair with at least " :<>: 'ShowType (FromPeano n) :<>: 'Text " elements at the top of the stack," :$$: 'Text "but the pair only contains " :<>: 'ShowType (FromPeano (CombedPairLeafCount pair)) :<>: 'Text " elements.") ('Text "Expected a pair at the top of the stack, but found: " :<>: 'ShowType pair)), SingI n, KnownPeano n)
+ Michelson.Typed.Instr: type ConstraintUnpairN (n :: Peano) (pair :: T) = (TypeErrorUnless (n >= ToPeano 2) ('Text "'UNPAIR n' expects n \8805 2"), TypeErrorUnless (CombedPairLeafCountIsAtLeast n pair) (If (IsPair pair) ('Text "'UNPAIR " :<>: 'ShowType (FromPeano n) :<>: 'Text "' expects a right-combed pair with at least " :<>: 'ShowType (FromPeano n) :<>: 'Text " elements at the top of the stack," :$$: 'Text "but the pair only contains " :<>: 'ShowType (FromPeano (CombedPairLeafCount pair)) :<>: 'Text " elements.") ('Text "Expected a pair at the top of the stack, but found: " :<>: 'ShowType pair)))
- Michelson.Typed.Instr: type ConstraintUpdateN (ix :: Peano) (pair :: T) = (TypeErrorUnless (CombedPairNodeIndexIsValid ix pair) (If (IsPair pair) ('Text "'UPDATE " :<>: 'ShowType (FromPeano ix) :<>: 'Text "' expects the 2nd element of the stack to be a right-combed pair with at least " :<>: 'ShowType (FromPeano ix + 1) :<>: 'Text " nodes," :$$: 'Text "but the pair only contains " :<>: 'ShowType (FromPeano (CombedPairNodeCount pair)) :<>: 'Text " nodes.") ('Text "Expected the 2nd element of the stack to be a pair, but found: " :<>: 'ShowType pair)), SingI ix, KnownPeano ix)
+ Michelson.Typed.Instr: type ConstraintUpdateN (ix :: Peano) (pair :: T) = (TypeErrorUnless (CombedPairNodeIndexIsValid ix pair) (If (IsPair pair) ('Text "'UPDATE " :<>: 'ShowType (FromPeano ix) :<>: 'Text "' expects the 2nd element of the stack to be a right-combed pair with at least " :<>: 'ShowType (FromPeano ix + 1) :<>: 'Text " nodes," :$$: 'Text "but the pair only contains " :<>: 'ShowType (FromPeano (CombedPairNodeCount pair)) :<>: 'Text " nodes.") ('Text "Expected the 2nd element of the stack to be a pair, but found: " :<>: 'ShowType pair)))
- Michelson.Typed.Polymorphic: mapOpFromList :: (MapOp c, KnownT b) => Value' instr c -> [Value' instr b] -> Value' instr (MapOpRes c b)
+ Michelson.Typed.Polymorphic: mapOpFromList :: (MapOp c, SingI b) => Value' instr c -> [Value' instr b] -> Value' instr (MapOpRes c b)
- Michelson.Typed.Scope: class (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t) => ConstantScope t
+ Michelson.Typed.Scope: class (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t, HasNoTicket t) => ConstantScope t
- Michelson.Typed.Scope: class (SingI t, HasNoOp t, HasNoBigMap t) => PackedValScope t
+ Michelson.Typed.Scope: class (SingI t, HasNoOp t, HasNoBigMap t, HasNoTicket t) => PackedValScope t
- Michelson.Typed.Scope: class (KnownT t, HasNoOp t, HasNoNestedBigMaps t) => ParameterScope t
+ Michelson.Typed.Scope: class (SingI t, HasNoOp t, HasNoNestedBigMaps t) => ParameterScope t
- Michelson.Typed.Scope: class (KnownT t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t) => StorageScope t
+ Michelson.Typed.Scope: class (SingI t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t) => StorageScope t
- Michelson.Typed.Scope: type ProperConstantBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t)
+ Michelson.Typed.Scope: type ProperConstantBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t, ForbidTicket t)
- Michelson.Typed.Scope: type ProperPackedValBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t)
+ Michelson.Typed.Scope: type ProperPackedValBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t, ForbidTicket t)
- Michelson.Typed.Scope: type ProperParameterBetterErrors t = (KnownT t, ForbidOp t, ForbidNestedBigMaps t)
+ Michelson.Typed.Scope: type ProperParameterBetterErrors t = (SingI t, ForbidOp t, ForbidNestedBigMaps t)
- Michelson.Typed.Scope: type ProperStorageBetterErrors t = (KnownT t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t)
+ Michelson.Typed.Scope: type ProperStorageBetterErrors t = (SingI t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t)
- Michelson.Typed.Sing: [STAddress] :: SingT 'TAddress
+ Michelson.Typed.Sing: [STAddress] :: SingT ('TAddress :: T)
- Michelson.Typed.Sing: [STBigMap] :: (KnownT a, KnownT b) => Sing a -> Sing b -> SingT ('TBigMap a b)
+ Michelson.Typed.Sing: [STBigMap] :: forall (n_a1EVW :: T) (n_a1EVX :: T). () => Sing n_a1EVW -> Sing n_a1EVX -> SingT ('TBigMap n_a1EVW n_a1EVX :: T)
- Michelson.Typed.Sing: [STBls12381Fr] :: SingT 'TBls12381Fr
+ Michelson.Typed.Sing: [STBls12381Fr] :: SingT ('TBls12381Fr :: T)
- Michelson.Typed.Sing: [STBls12381G1] :: SingT 'TBls12381G1
+ Michelson.Typed.Sing: [STBls12381G1] :: SingT ('TBls12381G1 :: T)
- Michelson.Typed.Sing: [STBls12381G2] :: SingT 'TBls12381G2
+ Michelson.Typed.Sing: [STBls12381G2] :: SingT ('TBls12381G2 :: T)
- Michelson.Typed.Sing: [STBool] :: SingT 'TBool
+ Michelson.Typed.Sing: [STBool] :: SingT ('TBool :: T)
- Michelson.Typed.Sing: [STBytes] :: SingT 'TBytes
+ Michelson.Typed.Sing: [STBytes] :: SingT ('TBytes :: T)
- Michelson.Typed.Sing: [STChainId] :: SingT 'TChainId
+ Michelson.Typed.Sing: [STChainId] :: SingT ('TChainId :: T)
- Michelson.Typed.Sing: [STContract] :: KnownT a => Sing a -> SingT ('TContract a)
+ Michelson.Typed.Sing: [STContract] :: forall (n_a1EVC :: T). () => Sing n_a1EVC -> SingT ('TContract n_a1EVC :: T)
- Michelson.Typed.Sing: [STInt] :: SingT 'TInt
+ Michelson.Typed.Sing: [STInt] :: SingT ('TInt :: T)
- Michelson.Typed.Sing: [STKeyHash] :: SingT 'TKeyHash
+ Michelson.Typed.Sing: [STKeyHash] :: SingT ('TKeyHash :: T)
- Michelson.Typed.Sing: [STKey] :: SingT 'TKey
+ Michelson.Typed.Sing: [STKey] :: SingT ('TKey :: T)
- Michelson.Typed.Sing: [STLambda] :: (KnownT a, KnownT b) => Sing a -> Sing b -> SingT ('TLambda a b)
+ Michelson.Typed.Sing: [STLambda] :: forall (n_a1EVO :: T) (n_a1EVP :: T). () => Sing n_a1EVO -> Sing n_a1EVP -> SingT ('TLambda n_a1EVO n_a1EVP :: T)
- Michelson.Typed.Sing: [STList] :: KnownT a => Sing a -> SingT ('TList a)
+ Michelson.Typed.Sing: [STList] :: forall (n_a1EVy :: T). () => Sing n_a1EVy -> SingT ('TList n_a1EVy :: T)
- Michelson.Typed.Sing: [STMap] :: (KnownT a, KnownT b) => Sing a -> Sing b -> SingT ('TMap a b)
+ Michelson.Typed.Sing: [STMap] :: forall (n_a1EVS :: T) (n_a1EVT :: T). () => Sing n_a1EVS -> Sing n_a1EVT -> SingT ('TMap n_a1EVS n_a1EVT :: T)
- Michelson.Typed.Sing: [STMutez] :: SingT 'TMutez
+ Michelson.Typed.Sing: [STMutez] :: SingT ('TMutez :: T)
- Michelson.Typed.Sing: [STNat] :: SingT 'TNat
+ Michelson.Typed.Sing: [STNat] :: SingT ('TNat :: T)
- Michelson.Typed.Sing: [STNever] :: SingT 'TNever
+ Michelson.Typed.Sing: [STNever] :: SingT ('TNever :: T)
- Michelson.Typed.Sing: [STOperation] :: SingT 'TOperation
+ Michelson.Typed.Sing: [STOperation] :: SingT ('TOperation :: T)
- Michelson.Typed.Sing: [STOption] :: KnownT a => Sing a -> SingT ('TOption a)
+ Michelson.Typed.Sing: [STOption] :: forall (n_a1EVw :: T). () => Sing n_a1EVw -> SingT ('TOption n_a1EVw :: T)
- Michelson.Typed.Sing: [STOr] :: (KnownT a, KnownT b) => Sing a -> Sing b -> SingT ('TOr a b)
+ Michelson.Typed.Sing: [STOr] :: forall (n_a1EVK :: T) (n_a1EVL :: T). () => Sing n_a1EVK -> Sing n_a1EVL -> SingT ('TOr n_a1EVK n_a1EVL :: T)
- Michelson.Typed.Sing: [STPair] :: (KnownT a, KnownT b) => Sing a -> Sing b -> SingT ('TPair a b)
+ Michelson.Typed.Sing: [STPair] :: forall (n_a1EVG :: T) (n_a1EVH :: T). () => Sing n_a1EVG -> Sing n_a1EVH -> SingT ('TPair n_a1EVG n_a1EVH :: T)
- Michelson.Typed.Sing: [STSet] :: KnownT a => Sing a -> SingT ('TSet a)
+ Michelson.Typed.Sing: [STSet] :: forall (n_a1EVA :: T). () => Sing n_a1EVA -> SingT ('TSet n_a1EVA :: T)
- Michelson.Typed.Sing: [STSignature] :: SingT 'TSignature
+ Michelson.Typed.Sing: [STSignature] :: SingT ('TSignature :: T)
- Michelson.Typed.Sing: [STString] :: SingT 'TString
+ Michelson.Typed.Sing: [STString] :: SingT ('TString :: T)
- Michelson.Typed.Sing: [STTimestamp] :: SingT 'TTimestamp
+ Michelson.Typed.Sing: [STTimestamp] :: SingT ('TTimestamp :: T)
- Michelson.Typed.Sing: [STUnit] :: SingT 'TUnit
+ Michelson.Typed.Sing: [STUnit] :: SingT ('TUnit :: T)
- Michelson.Typed.Sing: data SingT :: T -> Type
+ Michelson.Typed.Sing: data SingT z_a1EWL
- Michelson.Typed.Util: [PartlyPushableStorage] :: (StorageScope bms, StorageScope st) => Value bms -> Instr (bms : s) (st : s) -> PushableStorageSplit s st
+ Michelson.Typed.Util: [PartlyPushableStorage] :: (StorageScope heavy, StorageScope st) => Value heavy -> Instr (heavy : s) (st : s) -> PushableStorageSplit s st
- Michelson.Typed.Value: [VBigMap] :: forall k v instr. (KnownT k, KnownT v, Comparable k) => Map (Value' instr k) (Value' instr v) -> Value' instr ('TBigMap k v)
+ Michelson.Typed.Value: [VBigMap] :: forall k v instr. (SingI k, SingI v, Comparable k, HasNoBigMap v) => Maybe Natural -> Map (Value' instr k) (Value' instr v) -> Value' instr ('TBigMap k v)
- Michelson.Typed.Value: [VContract] :: forall arg instr. Address -> SomeEntrypointCallT arg -> Value' instr ('TContract arg)
+ Michelson.Typed.Value: [VContract] :: forall arg instr. (SingI arg, HasNoOp arg) => Address -> SomeEntrypointCallT arg -> Value' instr ('TContract arg)
- Michelson.Typed.Value: [VLam] :: forall inp out instr. (KnownT inp, KnownT out, forall i o. Show (instr i o), forall i o. Eq (instr i o), forall i o. NFData (instr i o)) => RemFail instr (inp : '[]) (out : '[]) -> Value' instr ('TLambda inp out)
+ Michelson.Typed.Value: [VLam] :: forall inp out instr. (SingI inp, SingI out, forall i o. Show (instr i o), forall i o. Eq (instr i o), forall i o. NFData (instr i o)) => RemFail instr (inp : '[]) (out : '[]) -> Value' instr ('TLambda inp out)
- Michelson.Typed.Value: [VList] :: forall t instr. KnownT t => [Value' instr t] -> Value' instr ('TList t)
+ Michelson.Typed.Value: [VList] :: forall t instr. SingI t => [Value' instr t] -> Value' instr ('TList t)
- Michelson.Typed.Value: [VMap] :: forall k v instr. (KnownT k, KnownT v, Comparable k) => Map (Value' instr k) (Value' instr v) -> Value' instr ('TMap k v)
+ Michelson.Typed.Value: [VMap] :: forall k v instr. (SingI k, SingI v, Comparable k) => Map (Value' instr k) (Value' instr v) -> Value' instr ('TMap k v)
- Michelson.Typed.Value: [VOption] :: forall t instr. KnownT t => Maybe (Value' instr t) -> Value' instr ('TOption t)
+ Michelson.Typed.Value: [VOption] :: forall t instr. SingI t => Maybe (Value' instr t) -> Value' instr ('TOption t)
- Michelson.Typed.Value: [VOr] :: forall l r instr. (KnownT l, KnownT r) => Either (Value' instr l) (Value' instr r) -> Value' instr ('TOr l r)
+ Michelson.Typed.Value: [VOr] :: forall l r instr. (SingI l, SingI r) => Either (Value' instr l) (Value' instr r) -> Value' instr ('TOr l r)
- Michelson.Typed.Value: [VSet] :: forall t instr. (KnownT t, Comparable t) => Set (Value' instr t) -> Value' instr ('TSet t)
+ Michelson.Typed.Value: [VSet] :: forall t instr. (SingI t, Comparable t) => Set (Value' instr t) -> Value' instr ('TSet t)
- Michelson.Typed.Value: type ComparabilityScope t = (KnownT t, Comparable t)
+ Michelson.Typed.Value: type ComparabilityScope t = (SingI t, Comparable t)
- Michelson.Typed.Value: valueTypeSanity :: Value' instr t -> Dict (KnownT t)
+ Michelson.Typed.Value: valueTypeSanity :: Value' instr t -> Dict (SingI t)
- Michelson.Typed.Value: withValueTypeSanity :: Value' instr t -> (KnownT t => a) -> a
+ Michelson.Typed.Value: withValueTypeSanity :: Value' instr t -> (SingI t => a) -> a
- Morley.Micheline.Binary: encodeExpression :: Expression -> ByteString
+ Morley.Micheline.Binary: encodeExpression :: Expression -> LByteString
- Morley.Micheline.Class: FromExpressionError :: UnpackError -> FromExpressionError
+ Morley.Micheline.Class: FromExpressionError :: Expression -> Text -> FromExpressionError
- Morley.Micheline.Expression: ExpressionSeq :: Seq Expression -> Expression
+ Morley.Micheline.Expression: ExpressionSeq :: [Expression] -> Expression
- Morley.Micheline.Expression: MichelinePrimAp :: MichelinePrimitive -> Seq Expression -> Seq Annotation -> MichelinePrimAp
+ Morley.Micheline.Expression: MichelinePrimAp :: MichelinePrimitive -> [Expression] -> [Annotation] -> MichelinePrimAp
- Morley.Micheline.Expression: [mpaAnnots] :: MichelinePrimAp -> Seq Annotation
+ Morley.Micheline.Expression: [mpaAnnots] :: MichelinePrimAp -> [Annotation]
- Morley.Micheline.Expression: [mpaArgs] :: MichelinePrimAp -> Seq Expression
+ Morley.Micheline.Expression: [mpaArgs] :: MichelinePrimAp -> [Expression]
- Util.Peano: [SS] :: (SingI n, KnownPeano n) => SingNat n -> SingNat ('S n)
+ Util.Peano: [SS] :: !SingNat n -> SingNat ('S n)
Files
- CHANGES.md +85/−0
- app/Main.hs +44/−21
- app/REPL.hs +23/−14
- morley.cabal +5/−2
- src/Michelson/Doc.hs +7/−7
- src/Michelson/ErrorPos.hs +11/−0
- src/Michelson/FailPattern.hs +8/−14
- src/Michelson/Interpret.hs +178/−111
- src/Michelson/Interpret/Pack.hs +21/−570
- src/Michelson/Interpret/Unpack.hs +24/−914
- src/Michelson/Macro.hs +42/−51
- src/Michelson/Optimizer.hs +106/−97
- src/Michelson/Parser.hs +43/−3
- src/Michelson/Parser/Annotations.hs +19/−10
- src/Michelson/Parser/Error.hs +1/−3
- src/Michelson/Parser/Ext.hs +2/−2
- src/Michelson/Parser/Instr.hs +36/−6
- src/Michelson/Parser/Let.hs +4/−2
- src/Michelson/Parser/Macro.hs +11/−16
- src/Michelson/Parser/Type.hs +10/−4
- src/Michelson/Parser/Value.hs +4/−4
- src/Michelson/Preprocess.hs +2/−2
- src/Michelson/Printer.hs +4/−4
- src/Michelson/Printer/Util.hs +18/−1
- src/Michelson/Runtime.hs +84/−46
- src/Michelson/Runtime/Dummy.hs +5/−1
- src/Michelson/Runtime/GState.hs +29/−6
- src/Michelson/Runtime/Import.hs +205/−0
- src/Michelson/Text.hs +17/−17
- src/Michelson/TypeCheck.hs +3/−0
- src/Michelson/TypeCheck/Error.hs +105/−60
- src/Michelson/TypeCheck/Ext.hs +17/−15
- src/Michelson/TypeCheck/Helpers.hs +72/−60
- src/Michelson/TypeCheck/Instr.hs +222/−140
- src/Michelson/TypeCheck/TypeCheck.hs +44/−19
- src/Michelson/TypeCheck/TypeCheckedOp.hs +5/−5
- src/Michelson/TypeCheck/Types.hs +77/−57
- src/Michelson/TypeCheck/Value.hs +149/−45
- src/Michelson/Typed.hs +1/−0
- src/Michelson/Typed/Aliases.hs +0/−4
- src/Michelson/Typed/Annotation.hs +25/−13
- src/Michelson/Typed/Convert.hs +267/−117
- src/Michelson/Typed/Doc.hs +7/−0
- src/Michelson/Typed/Entrypoints.hs +43/−30
- src/Michelson/Typed/Existential.hs +79/−0
- src/Michelson/Typed/Extract.hs +48/−22
- src/Michelson/Typed/Haskell/Doc.hs +22/−14
- src/Michelson/Typed/Haskell/Instr/Product.hs +16/−16
- src/Michelson/Typed/Haskell/Instr/Sum.hs +15/−15
- src/Michelson/Typed/Haskell/LooseSum.hs +8/−7
- src/Michelson/Typed/Haskell/Value.hs +84/−30
- src/Michelson/Typed/Instr.hs +243/−97
- src/Michelson/Typed/Origination.hs +56/−7
- src/Michelson/Typed/Polymorphic.hs +7/−7
- src/Michelson/Typed/Scope.hs +206/−57
- src/Michelson/Typed/Sing.hs +63/−205
- src/Michelson/Typed/T.hs +6/−0
- src/Michelson/Typed/Util.hs +95/−82
- src/Michelson/Typed/Value.hs +31/−44
- src/Michelson/Untyped/Annotation.hs +51/−19
- src/Michelson/Untyped/Entrypoints.hs +19/−14
- src/Michelson/Untyped/Instr.hs +10/−4
- src/Michelson/Untyped/OpSize.hs +6/−0
- src/Michelson/Untyped/Type.hs +41/−14
- src/Michelson/Untyped/Value.hs +11/−1
- src/Morley/Micheline/Binary.hs +31/−28
- src/Morley/Micheline/Class.hs +874/−73
- src/Morley/Micheline/Expression.hs +77/−16
- src/Tezos/Address.hs +65/−62
- src/Tezos/Core.hs +18/−18
- src/Tezos/Crypto.hs +12/−8
- src/Tezos/Crypto/BLS12381.hs +19/−13
- src/Tezos/Crypto/Ed25519.hs +2/−2
- src/Tezos/Crypto/P256.hs +2/−2
- src/Tezos/Crypto/Secp256k1.hs +2/−2
- src/Tezos/Crypto/Util.hs +24/−17
- src/Util/CLI.hs +53/−7
- src/Util/Peano.hs +5/−25
- src/Util/PeanoNatural.hs +84/−0
- src/Util/Positive.hs +4/−4
- src/Util/Sing.hs +93/−0
- src/Util/Type.hs +25/−25
- src/Util/TypeLits.hs +17/−0
- src/Util/Typeable.hs +2/−18
CHANGES.md view
@@ -2,6 +2,91 @@ ========== <!-- Append new entries here --> +1.15.0+======+* [!878](https://gitlab.com/morley-framework/morley/-/merge_requests/878)+ + Fixed behavior of `packValue` to match the `tezos-client hash data`+ behavior.+ + Pair conversion in `instance ToExpression Untyped.Value` always produces+ `ExpressionPrim` instead `ExpressionSeq`. Optimization of right-combed pairs+ moved to `Michelson.Typed.Convert` and depends on `UntypingOptions`.+* [!880](https://gitlab.com/morley-framework/morley/-/merge_requests/880)+ + Fixed loss of type annotations in serialization of right-combed pairs.+* [!795](https://gitlab.com/morley-framework/morley/-/merge_requests/795)+ + Changed typecheck exception messages.+ + Changed Buildable instances for several datatypes to be based on+ RenderDoc instances.+ + Changed the regexp in scripts/regenerate-gold-files-for-verbose-typechecking.sh+ so it does not ommit extra space in .gold files on MacOS.+* [!863](https://gitlab.com/morley-framework/morley/-/merge_requests/863)+ + Removed conversion from variable anotations to field anontations in+ `PAIRN` instruction.+* [!856](https://gitlab.com/morley-framework/morley/-/merge_requests/856)+ + Removed `Typeable` constrains from singletons generated by `T`.+ + Added the `Util.Sing` module with functions that allow equality comparison+ using `SDecide`.+* [!858](https://gitlab.com/morley-framework/morley/-/merge_requests/858)+ + Added `SomeStorage` type.+ + Modified `runContract` to return `SomeStorage`.+* [!833](https://gitlab.com/morley-framework/morley/-/merge_requests/833)+ + Fixed `ContainsBigMap` and `ContainsNestedBigMaps` instances for `TContract`.+ + Added `Data` instance to `BigMap` and `BigMapId`.+ + Added `requireEqT`, `castM` and `gcastM` to `Util.Typeable`.+* [!859](https://gitlab.com/morley-framework/morley/-/merge_requests/859)+ + Added `BigMapId` type.+ + Added ID to `VBigMap` and `BigMap`.+ + Updated interpreter to assign a unique big_map ID to each big_map, and+ keep track of how many big_maps have been created with a `BigMapCounter`.+ + Deleted `dfsValue`.+ + Renamed `dfsModifyValue` and `dfsFoldValue` to `dfsMapValue` and `dfsFoldMapValue`.+ + Added `dfsTraverseValue` and `dfsFoldMapValueM`.+* [!840](https://gitlab.com/morley-framework/morley/-/merge_requests/840)+ + Changed behaviour of deserializer: it fails if the expression contains+ more annotations than expected instead of ignoring them.+ + Changed behaviour of serializer: it uses list notation for all pair+ values, not just for right-combed ones.+* [!816](https://gitlab.com/morley-framework/morley/-/merge_requests/816)+ + Removed the `SingI` and `KnownPeano` constraints by introducting the+ `PeanoNatural` data type.+ + The similar updates for `SingT`. Removed the `SingI` constraints in the+ constructors of `SingT`+* [!855](https://gitlab.com/morley-framework/morley/-/merge_requests/855)+ + Fix custom error arguments comparison in nettest by converting them+ to `Value t` before checking for equality.+* [!830](https://gitlab.com/morley-framework/morley/-/merge_requests/830)+ + Added the contract's address to some of the `ExecutorError'`+ constructors: `EEIllTypedParameter` and `EEUnexpectedParameterType`.+* [!820](https://gitlab.com/morley-framework/morley/-/merge_requests/820)+ + Moved functions for contract importing (like `importContract`) from cleveland.+ + Added functions for values importing (`readValue`, `importValue` and others).+* [!832](https://gitlab.com/morley-framework/morley/-/merge_requests/832)+ + Add tickets feature.+ + Add dupable restriction to `DUP`-like instructions.+* [!838](https://gitlab.com/morley-framework/morley/-/merge_requests/838)+ + All unsafe functions and data constructors now contain "unsafe" word+ at prefix position. E.g `UnsafeUParam`, `unsafeParseKeyHash`.+* [!828](https://gitlab.com/morley-framework/morley/-/merge_requests/828)+ + Fix bug in serialization of instructions with variable annotations:+ `EMPTY_SET`, `EMPTY_MAP`, `PUSH`, `LAMBDA`, `CAST`, `CONTRACT`.+* [!770](https://gitlab.com/morley-framework/morley/-/merge_requests/770)+ + Added `Fn` meta-instruction to support Morley's typed stack function in+ typed form.+ + Added `STACKTYPE` as a typed `ExtInstr`.+* [!822](https://gitlab.com/morley-framework/morley/-/merge_requests/822)+ + Add new `edo` instruction: `UNPAIR`.+ + Rename `UNPAIR` macro to `UNPAPAIR`.+ + Expand `UNPAPAIR` macros to `UNPAIR` instructions.+ + The `Seq` constructor can now be used as a right-associative operator.+ + Optimize `DUP; CAR; DIP { CDR }` to `UNPAIR`+ + Optimize `DUP; CDR; DIP { CAR }` to `UNPAIR; SWAP`+* [!825](https://gitlab.com/morley-framework/morley/-/merge_requests/825)+ + Fix bug in morley executable's `repl` command: consume the entire input+ when parsing an instruction.+ + Fix bug in the handling of special annotations for `CAR`/`CDR`.+ + Fix bug in parsing of `PAIR` instructions with exactly 1 field ann.+ + Preserve `CAR`/`CDR`'s original annotations when converting them back to+ michelson/binary/json.+ 1.14.0 ====== * [!799](https://gitlab.com/morley-framework/morley/-/merge_requests/799)
app/Main.hs view
@@ -6,14 +6,13 @@ ( main ) where -import Data.Default (def) import qualified Data.Text.Lazy.IO.Utf8 as Utf8 (writeFile) import Data.Version (showVersion) import Fmt (pretty) import Named (arg, argF, (!)) import Options.Applicative- (command, execParser, footerDoc, fullDesc, header, help, helper, info, infoOption, long,- progDesc, short, subparser, switch)+ (execParser, footerDoc, fullDesc, header, help, helper, info, infoOption, long, progDesc, short,+ subparser, switch) import qualified Options.Applicative as Opt import Options.Applicative.Help.Pretty (Doc, linebreak) import Paths_morley (version)@@ -23,16 +22,17 @@ import Michelson.Printer (printSomeContract, printUntypedContract) import Michelson.Runtime (TxData(..), originateContract, prepareContract, runContract, transfer) import Michelson.Runtime.GState (genesisAddress)-import Michelson.TypeCheck (tcVerbose, typeCheckContract)-import Michelson.TypeCheck.Types (SomeContract(..), mapSomeContract)-import Michelson.Typed (Contract(..))+import Michelson.TypeCheck (tcVerbose, typeCheckContract, typeCheckingWith)+import qualified Michelson.TypeCheck as TypeCheck+import Michelson.TypeCheck.Types (mapSomeContract)+import Michelson.Typed (Contract(..), SomeContract(..)) import qualified Michelson.Untyped as U import Morley.CLI import REPL import Tezos.Address (Address) import Tezos.Core (Mutez, Timestamp(..), unsafeMkMutez) import Tezos.Crypto-import Util.CLI (outputOption)+import Util.CLI (mkCommandParser, outputOption) import Util.Main (wrapMain) import Util.Named @@ -62,12 +62,13 @@ data TypeCheckOptions = TypeCheckOptions { tcoContractFile :: Maybe FilePath- , tcoVerbose :: Bool+ , tcoTcOptions :: TypeCheck.TypeCheckOptions } data RunOptions = RunOptions { roContractFile :: Maybe FilePath , roDBPath :: FilePath+ , roTcOptions :: TypeCheck.TypeCheckOptions , roStorageValue :: U.Value , roTxData :: TxData , roVerbose :: Bool@@ -81,6 +82,7 @@ data OriginateOptions = OriginateOptions { ooContractFile :: Maybe FilePath , ooDBPath :: FilePath+ , ooTcOptions :: TypeCheck.TypeCheckOptions , ooOriginator :: Address , ooDelegate :: Maybe KeyHash , ooStorageValue :: U.Value@@ -90,6 +92,7 @@ data TransferOptions = TransferOptions { toDBPath :: FilePath+ , toTcOptions :: TypeCheck.TypeCheckOptions , toDestination :: Address , toTxData :: TxData , toNow :: Maybe Timestamp@@ -110,11 +113,6 @@ analyzeSubCmd <> replSubCmd where- mkCommandParser commandName parser desc =- command commandName $- info (helper <*> parser) $- progDesc desc- typecheckSubCmd = mkCommandParser "typecheck" (TypeCheck <$> typeCheckOptions) $@@ -175,10 +173,19 @@ long "dry-run" <> help "Do not write updated DB to DB file" + typeCheckOptionsOption :: Opt.Parser TypeCheck.TypeCheckOptions+ typeCheckOptionsOption = do+ tcVerbose <- verboseFlag+ tcStrict <- fmap not . switch $+ long "typecheck-lax" <>+ help "Whether actions permitted in `tezos-client run` but forbidden in \+ \e.g. `tezos-client originate` should be allowed here"+ return TypeCheck.TypeCheckOptions{..}+ typeCheckOptions :: Opt.Parser TypeCheckOptions typeCheckOptions = TypeCheckOptions <$> optional contractFileOption- <*> verboseFlag+ <*> typeCheckOptionsOption defaultBalance :: Mutez defaultBalance = unsafeMkMutez 4000000@@ -197,6 +204,7 @@ RunOptions <$> optional contractFileOption <*> dbPathOption+ <*> typeCheckOptionsOption <*> valueOption Nothing (#name .! "storage") (#help .! "Initial storage of a running contract") <*> txDataOption@@ -213,6 +221,7 @@ OriginateOptions <$> optional contractFileOption <*> dbPathOption+ <*> typeCheckOptionsOption <*> addressOption (Just genesisAddress) (#name .! "originator") (#help .! "Contract's originator") <*> optional@@ -228,6 +237,7 @@ transferOptions :: Opt.Parser TransferOptions transferOptions = do toDBPath <- dbPathOption+ toTcOptions <- typeCheckOptionsOption toDestination <- addressOption Nothing (#name .! "to") (#help .! "Destination address")@@ -239,6 +249,13 @@ toDryRun <- dryRunFlag pure TransferOptions {..} +-- | Most permitting options, when we don't care much about typechecking.+laxTcOptions :: TypeCheck.TypeCheckOptions+laxTcOptions = TypeCheck.TypeCheckOptions+ { TypeCheck.tcVerbose = False+ , TypeCheck.tcStrict = False+ }+ ---------------------------------------------------------------------------- -- Actual main ----------------------------------------------------------------------------@@ -270,24 +287,29 @@ Optimize OptimizeOptions{..} -> do untypedContract <- prepareContract optoContractFile checkedContract <-- either throwM pure $ typeCheckContract untypedContract def+ either throwM pure . typeCheckingWith laxTcOptions $+ typeCheckContract untypedContract 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 def+ either throwM pure . typeCheckingWith laxTcOptions $+ typeCheckContract untypedContract putTextLn $ pretty $ analyze (cCode contract) TypeCheck TypeCheckOptions{..} -> do morleyContract <- prepareContract tcoContractFile- contract <- either throwM pure- $ typeCheckContract morleyContract def{ tcVerbose = tcoVerbose }- when tcoVerbose (putStrLn $ printSomeContract False contract)+ -- At the moment of writing, 'tcStrict' option does not change anything+ -- because it affects only values parsing; but this may change+ contract <- either throwM pure . typeCheckingWith tcoTcOptions+ $ typeCheckContract morleyContract+ when (TypeCheck.tcVerbose tcoTcOptions) $+ putStrLn $ printSomeContract False contract putTextLn "Contract is well-typed" Run RunOptions {..} -> do michelsonContract <- prepareContract roContractFile- void $ runContract roNow roLevel roMaxSteps roInitBalance roDBPath roStorageValue michelsonContract roTxData+ void $ runContract roNow roLevel roMaxSteps roInitBalance roDBPath roTcOptions roStorageValue michelsonContract roTxData ! #verbose roVerbose ! #dryRun (not roWrite) Originate OriginateOptions {..} -> do@@ -295,6 +317,7 @@ addr <- originateContract ooDBPath+ ooTcOptions ooOriginator ooDelegate ooBalance@@ -303,7 +326,7 @@ ! #verbose ooVerbose putTextLn $ "Originated contract " <> pretty addr Transfer TransferOptions {..} -> do- transfer toNow toLevel toMaxSteps toDBPath toDestination toTxData+ transfer toNow toLevel toMaxSteps toDBPath toTcOptions toDestination toTxData ! #verbose toVerbose ! #dryRun toDryRun REPL -> runRepl
app/REPL.hs view
@@ -21,7 +21,6 @@ import qualified Data.ByteString.Lazy as BSL import Data.List (stripPrefix) import Data.Text (strip)-import Data.Typeable (cast) import Data.Vinyl (Rec(..)) import Fmt (pretty) import System.Console.Haskeline@@ -29,18 +28,21 @@ import Michelson.Interpret (interpretInstr) import Michelson.Macro (ParsedOp, expandList)-import Michelson.Parser (errorBundlePretty, ops, parseExpandValue, type_)+import Michelson.Parser (errorBundlePretty, ops, parseExpandValue, parseNoEnv, type_) import Michelson.Parser.Types (noLetEnv) import Michelson.Printer (printDoc, printTypedValue) import Michelson.Printer.Util (doesntNeedParens) import Michelson.Runtime.Dummy-import Michelson.TypeCheck (SomeInstr(..), SomeInstrOut(..), getWTP, runTypeCheckIsolated)+import Michelson.TypeCheck+ (SomeInstr(..), SomeInstrOut(..), TypeCheckOptions(..), getWTP, runTypeCheckIsolated,+ typeCheckingWith) import Michelson.TypeCheck.Instr (typeCheckList, typeCheckParameter) import Michelson.TypeCheck.Types (HST(..), NotWellTyped(..)) import qualified Michelson.Typed as T import qualified Michelson.Untyped as U+import Util.Sing (castSing) -data SomeStack = forall t. Typeable t => SomeStack+data SomeStack = forall t. T.SingI t => SomeStack { stValues :: (Rec T.Value t) , stTypes :: HST t }@@ -95,8 +97,9 @@ Right parsedOps -> do let expandedOps = expandList parsedOps lift get >>= \case- SomeStack {..} -> case cast stTypes of- Just hstInp -> case runTypeCheckIsolated $ typeCheckList expandedOps hstInp of+ SomeStack {..} -> case castSing stTypes of+ Just hstInp -> case typeCheckingWith tcOptions . runTypeCheckIsolated $+ typeCheckList expandedOps hstInp of Right someInstr -> do case someInstr of _ :/ (instr ::: hstOut)-> case interpretInstr dummyContractEnv instr stValues of@@ -127,26 +130,32 @@ emptyStack = SomeStack RNil SNil parseInstructions :: Text -> Either Text [ParsedOp]-parseInstructions src = let- codeParser = runReaderT ops noLetEnv- in case parse codeParser "" src of+parseInstructions src =+ case parseNoEnv ops "" src of Right p -> Right p Left err -> Left (toText $ errorBundlePretty err) +tcOptions :: TypeCheckOptions+tcOptions = TypeCheckOptions+ { tcVerbose = False+ , tcStrict = False+ }+ -- helpers addValueToHST- :: forall t xs. Typeable xs+ :: forall t xs. T.SingI xs => T.Value t -> HST xs- -> Either Text (T.Dict (Typeable (t ': xs)), HST (t ': xs))+ -> Either Text (T.Dict (T.SingI (t ': xs)), HST (t ': xs)) addValueToHST v hstIn = case T.valueTypeSanity v of T.Dict -> case getWTP @t of Right wtpDict -> Right (T.Dict, (T.starNotes @t, wtpDict, U.noAnn) ::& hstIn)- Left (NotWellTyped t) -> let+ Left (NotWellTyped t cause) -> let U.Ty t' tann = T.toUType t in Left $ "Value of type '" <> (renderT t' (U.fullAnnSet [tann] [] []))- <> "' is not well typed in the provided Value."+ <> "' is not well typed in the provided Value because it "+ <> pretty cause <> "." renderType :: T.SingI t => T.Notes t -> U.VarAnn -> Text renderType notes vann = let@@ -200,7 +209,7 @@ buildStack (Right (SomeStack stk hst)) (txVal, txTyp) = case (parseExpandValue txVal, parse (runReaderT type_ noLetEnv) "" txTyp) of (Right val, Right typ) ->- case typeCheckParameter mempty typ val of+ case typeCheckingWith tcOptions $ typeCheckParameter mempty typ val of Right (T.SomeValue tVal) -> case addValueToHST tVal hst of Right (T.Dict, newHst) -> Right $ SomeStack (tVal :& stk) newHst
morley.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: morley-version: 1.14.0+version: 1.15.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@@ -66,6 +66,7 @@ Michelson.Runtime Michelson.Runtime.Dummy Michelson.Runtime.GState+ Michelson.Runtime.Import Michelson.Runtime.TxData Michelson.Text Michelson.TypeCheck@@ -85,6 +86,7 @@ Michelson.Typed.Convert Michelson.Typed.Doc Michelson.Typed.Entrypoints+ Michelson.Typed.Existential Michelson.Typed.Extract Michelson.Typed.Haskell Michelson.Typed.Haskell.Compatibility@@ -149,7 +151,9 @@ Util.Named Util.Num Util.Peano+ Util.PeanoNatural Util.Positive+ Util.Sing Util.Text Util.TH Util.Type@@ -230,7 +234,6 @@ aeson , base-noprelude >=4.7 && <5 , bytestring- , data-default , fmt , haskeline , megaparsec >=7.0.0
src/Michelson/Doc.hs view
@@ -321,17 +321,17 @@ "Doc items section: " <> show (typeRep $ Proxy @d) <> " / " <> show (length ds) <> " item(s)" -appendDocSectionUnsafe+unsafeAppendDocSection :: HasCallStack => DocSection -> DocSection -> DocSection-appendDocSectionUnsafe (DocSection ls) (DocSection rs) =- DocSection $ appendDocSectionUnsafeImpl ls (toList rs)+unsafeAppendDocSection (DocSection ls) (DocSection rs) =+ DocSection $ unsafeAppendDocSectionImpl ls (toList rs) -appendDocSectionUnsafeImpl+unsafeAppendDocSectionImpl :: forall d1 d2. (Typeable d1, Typeable d2, HasCallStack) => NonEmpty d1 -> [d2] -> NonEmpty d1-appendDocSectionUnsafeImpl (l :| ls) rs =+unsafeAppendDocSectionImpl (l :| ls) rs = let rs' = rs <&> \r -> cast r ?: onTypeMismatch in l :| ls <> rs' where@@ -496,14 +496,14 @@ { cdContents = M.merge M.preserveMissing M.preserveMissing- (M.zipWithMatched $ \_k l r -> appendDocSectionUnsafe l r)+ (M.zipWithMatched $ \_k l r -> unsafeAppendDocSection l r) (cdContents cd1) (cdContents cd2) , cdDefinitions = M.merge M.preserveMissing M.preserveMissing (M.zipWithMatched $ \_k (DocSection ls) (DocSection rs) -> let removeDups = filter $ not . (`isDefinedIn` cdDefinitionIds cd1) . deItem- in DocSection $ appendDocSectionUnsafeImpl ls (removeDups $ toList rs)+ in DocSection $ unsafeAppendDocSectionImpl ls (removeDups $ toList rs) ) (cdDefinitions cd1) (cdDefinitions cd2) , cdDefinitionsSet =
src/Michelson/ErrorPos.hs view
@@ -18,9 +18,13 @@ import Data.Default (Default(..)) import qualified Data.Text as T import Fmt (Buildable (..))+import Michelson.Printer.Util (RenderDoc (..), renderAnyBuildable)+import Text.PrettyPrint.Leijen.Text + import Util.Aeson + newtype Pos = Pos {unPos :: Word} deriving stock (Eq, Ord, Show, Generic, Data) @@ -61,6 +65,13 @@ { icsCallStack :: LetCallStack , icsSrcPos :: SrcPos } deriving stock (Eq, Ord, Show, Generic, Data)++instance RenderDoc InstrCallStack where+ renderDoc _ InstrCallStack{icsCallStack, icsSrcPos = SrcPos (Pos row) (Pos col)} =+ "Error occurred on line" <+> (renderAnyBuildable (row + 1)) <+> "char" <+> (renderAnyBuildable (col + 1))+ <> case icsCallStack of+ [] -> "."+ _ -> " inside these let defenitions:" <+> (list $ fmap (text . show) icsCallStack) <> "." instance NFData InstrCallStack
src/Michelson/FailPattern.hs view
@@ -15,25 +15,19 @@ , typicalFailWithTag , isTypicalFailWith , modifyTypicalFailWith-- , ConstantScope' ) where +import Data.Singletons (withSingI)+ import Michelson.Text (MText) import Michelson.Typed --- | We need this class to pass it to 'SomeConstrainedValue'.--- 'ConstantScope' is needed because we push a value and 'Typeable' is--- needed for 'FAILWITH'.-class (Typeable a, ConstantScope a) => ConstantScope' a-instance (Typeable a, ConstantScope a) => ConstantScope' a- -- | This data type captures typical ways to use `FAILWITH` instruction. -- Each constructor corresponds to a usage pattern. data TypicalFailWith = FailWithString MText -- ^ Push a constant string and fail with it.- | FailWithConstantPair MText (SomeConstrainedValue ConstantScope')+ | FailWithConstantPair MText (SomeConstrainedValue ConstantScope) -- ^ Push a constant pair where the first item is a string and the -- second one is an arbitrary constant. Fail afterwards. | FailWithStackValue MText@@ -75,7 +69,7 @@ | VPair (VString str, secondItem) <- v = -- We need to pattern match to deduce `singI` for second item of the pair. case sing @t of- STPair {} -> Just (FailWithConstantPair str (SomeConstrainedValue secondItem))+ STPair l r -> withSingI l $ withSingI r $ Just (FailWithConstantPair str (SomeConstrainedValue secondItem)) | otherwise = Nothing -- | If given instruction ends with a typical 'FAILWITH' usage, modify@@ -83,7 +77,7 @@ -- return any value, not necessarily a string. modifyTypicalFailWith :: HasCallStack- => (MText -> SomeConstrainedValue ConstantScope')+ => (MText -> SomeConstrainedValue ConstantScope) -> Instr inp out -> Instr inp out modifyTypicalFailWith f = modifyTypicalFailWith' . linearizeLeft@@ -103,7 +97,7 @@ | _ :: Value a <- v , _ :: Instr (b ': s) ('TPair a b ': s) <- i1 -> case sing @('TPair a b) of- STPair {} -> case isStringValue v of+ STPair l r -> withSingI l $ withSingI r $ case isStringValue v of Just (f -> SomeConstrainedValue v') -> PUSH v' `Seq` PAIR `Seq` FAILWITH Nothing ->@@ -112,7 +106,7 @@ | _ :: Value a <- v , _ :: Instr s0 ('TPair a b ': s) <- i1 -> case sing @('TPair a b) of- STPair {} -> Seq i0 $ case isStringValue v of+ STPair l r -> withSingI l $ withSingI r $ Seq i0 $ case isStringValue v of Just (f -> SomeConstrainedValue v') -> PUSH v' `Seq` PAIR `Seq` FAILWITH Nothing ->@@ -123,7 +117,7 @@ i -> i onPush ::- (HasCallStack, Typeable v, ConstantScope v) => Value v -> Instr inp out+ (HasCallStack, ConstantScope v) => Value v -> Instr inp out onPush v = case isTypicalErrorConstant v of Just (FailWithString (f -> SomeConstrainedValue v')) -> PUSH v' `Seq` FAILWITH Just (FailWithConstantPair (f -> SomeConstrainedValue v') (SomeConstrainedValue arg)) ->
src/Michelson/Interpret.hs view
@@ -37,16 +37,16 @@ , initInterpreterState , handleContractReturn , runInstrImpl+ , assignBigMapIds ) where import Prelude hiding (EQ, GT, LT) -import Control.Lens (makeLensesFor)+import Control.Lens (makeLensesFor, traverseOf, (<<+=)) import Control.Monad.Except (MonadError, throwError) import Data.Default (Default(..)) import qualified Data.Map as Map import qualified Data.Set as Set-import Data.Singletons (Sing) import Data.Vinyl (Rec(..), (<+>)) import Data.Vinyl.Recursive (rmap) import Fmt (Buildable(build), Builder, blockListF, prettyLn)@@ -57,18 +57,72 @@ import Michelson.TypeCheck (SomeParamType(..), TcOriginatedContracts, matchTypes) import Michelson.Typed hiding (Branch(..)) import qualified Michelson.Typed as T-import Michelson.Typed.Origination (OriginationOperation(..), mkOriginationOperationHash)-import Michelson.Untyped.Annotation (annQ)+import Michelson.Typed.Origination+ (OperationHash(..), OriginationOperation(..), mkContractAddress, mkOriginationOperationHash) import qualified Michelson.Untyped as U-import Tezos.Address (Address(..), GlobalCounter(..), OriginationIndex(..), mkContractAddress)+import Michelson.Untyped.Annotation (annQ)+import Tezos.Address (Address(..), GlobalCounter(..), OriginationIndex(..)) import Tezos.Core (ChainId, Mutez, Timestamp) import Tezos.Crypto (KeyHash, blake2b, checkSignature, hashKey, keccak, sha256, sha3, sha512) import Tezos.Crypto.BLS12381 (checkPairing)-import Util.Peano (LongerThan, Peano, SingNat(SS, SZ))+import Util.Peano (LongerThan, Peano)+import Util.PeanoNatural (PeanoNatural(..))+import Util.Sing (eqParamSing) import Util.TH import Util.Type import Util.Typeable +-- | Morley logs for interpreter state that are stored in reverse order.+newtype MorleyLogs = MorleyLogs [Text]+ deriving stock (Eq, Show, Generic)+ deriving newtype Default++pickMorleyLogs :: MorleyLogs -> [Text]+pickMorleyLogs (MorleyLogs logs) = reverse logs++instance Buildable MorleyLogs where+ build = blockListF . pickMorleyLogs++instance NFData MorleyLogs++noMorleyLogs :: MorleyLogs+noMorleyLogs = MorleyLogs []++newtype RemainingSteps = RemainingSteps Word64+ deriving stock (Show, Generic)+ deriving newtype (Eq, Ord, Buildable, Num)++instance NFData RemainingSteps++data InterpreterState = InterpreterState+ { isMorleyLogs :: MorleyLogs+ , isRemainingSteps :: RemainingSteps+ , isOriginationNonce :: OriginationIndex+ , isBigMapCounter :: BigMapCounter+ } deriving stock (Show, Generic)++instance NFData InterpreterState+makeLensesFor+ [ ("isMorleyLogs", "isMorleyLogsL")+ , ("isBigMapCounter", "isBigMapCounterL")+ ]+ ''InterpreterState++data StkEl t = StkEl+ { seValue :: Value t+ , seVarAnn :: U.VarAnn+ , seNotes :: Notes t+ } deriving stock (Eq, Show)++makeLensesFor+ [ ("seValue", "seValueL")+ , ("seVarAnn", "seVarAnnL")+ ]+ ''StkEl++starNotesStkEl :: forall t. Value t -> StkEl t+starNotesStkEl v = StkEl v U.noAnn $ withValueTypeSanity v $ starNotes @t+ -- | Environment for contract execution. data ContractEnv = ContractEnv { ceNow :: Timestamp@@ -92,7 +146,7 @@ -- ^ Distribution of voting power. , ceChainId :: ChainId -- ^ Identifier of the current chain.- , ceOperationHash :: Maybe U.OperationHash+ , ceOperationHash :: Maybe OperationHash -- ^ Hash of the currently executed operation, required for -- correct contract address computation in 'CREATE_CONTRACT' instruction. , ceGlobalCounter :: GlobalCounter@@ -105,7 +159,7 @@ -- | Represents @[FAILED]@ state of a Michelson program. Contains -- value that was on top of the stack when @FAILWITH@ was called. data MichelsonFailed where- MichelsonFailedWith :: (KnownT t, ConstantScope t) => T.Value t -> MichelsonFailed+ MichelsonFailedWith :: (SingI t, ConstantScope t) => T.Value t -> MichelsonFailed MichelsonArithError :: (Typeable n, Typeable m, Typeable instr) => ArithError (Value' instr n) (Value' instr m) -> MichelsonFailed@@ -115,7 +169,7 @@ deriving stock instance Show MichelsonFailed instance Eq MichelsonFailed where- MichelsonFailedWith v1 == MichelsonFailedWith v2 = v1 `eqParam1` v2+ MichelsonFailedWith v1 == MichelsonFailedWith v2 = v1 `eqParamSing` v2 MichelsonFailedWith _ == _ = False MichelsonArithError ae1 == MichelsonArithError ae2 = ae1 `eqParam2` ae2 MichelsonArithError _ == _ = False@@ -170,22 +224,6 @@ , iurNewState = st } --- | Morley logs for interpreter state that are stored in reverse order.-newtype MorleyLogs = MorleyLogs [Text]- deriving stock (Eq, Show, Generic)- deriving newtype Default--pickMorleyLogs :: MorleyLogs -> [Text]-pickMorleyLogs (MorleyLogs logs) = reverse logs--instance Buildable MorleyLogs where- build = blockListF . pickMorleyLogs--instance NFData MorleyLogs--noMorleyLogs :: MorleyLogs-noMorleyLogs = MorleyLogs []- type ContractReturn st = (Either MichelsonFailed ([Operation], T.Value st), InterpreterState) @@ -226,7 +264,7 @@ -> T.Value st -> T.Notes st -> Rec StkEl (ContractInp param st)-mkInitStack param T.ParamNotesUnsafe{..} st stNotes = StkEl+mkInitStack param T.UnsafeParamNotes{..} st stNotes = StkEl (T.VPair (param, st)) U.noAnn (T.NTPair U.noAnn (U.convAnn pnRootAnn) U.noAnn [annQ|parameter|] [annQ|storage|] pnNotes stNotes)@@ -241,13 +279,14 @@ -> EntrypointCallT cp arg -> T.Value arg -> T.Value st+ -> BigMapCounter -> ContractEnv -> ContractReturn st-interpret contract epc param initSt env =- interpret' contract epc param initSt env (initInterpreterState env)+interpret contract epc param initSt bmCounter env =+ interpret' contract epc param initSt env (initInterpreterState bmCounter env) -initInterpreterState :: ContractEnv -> InterpreterState-initInterpreterState env = InterpreterState def (ceMaxSteps env) (OriginationIndex 0)+initInterpreterState :: BigMapCounter -> ContractEnv -> InterpreterState+initInterpreterState bmCounter env = InterpreterState def (ceMaxSteps env) (OriginationIndex 0) bmCounter -- | Interpret an instruction in vacuum, putting no extra contraints on -- its execution.@@ -278,25 +317,12 @@ { isMorleyLogs = MorleyLogs [] , isRemainingSteps = 9999999999 , isOriginationNonce = OriginationIndex 0+ , isBigMapCounter = 0 } data SomeItStack where SomeItStack :: T.ExtInstr inp -> Rec StkEl inp -> SomeItStack -newtype RemainingSteps = RemainingSteps Word64- deriving stock (Show, Generic)- deriving newtype (Eq, Ord, Buildable, Num)--instance NFData RemainingSteps--data InterpreterState = InterpreterState- { isMorleyLogs :: MorleyLogs- , isRemainingSteps :: RemainingSteps- , isOriginationNonce :: OriginationIndex- } deriving stock (Show, Generic)--instance NFData InterpreterState- type EvalOp a = ExceptT MichelsonFailed (ReaderT ContractEnv@@ -337,15 +363,6 @@ , MonadError MichelsonFailed m ) -data StkEl t = StkEl- { seValue :: Value t- , seVarAnn :: U.VarAnn- , seNotes :: Notes t- } deriving stock (Eq, Show)--starNotesStkEl :: forall t. Value t -> StkEl t-starNotesStkEl v = StkEl v U.noAnn $ withValueTypeSanity v $ starNotes @t- type InstrRunner m = forall inp out. Instr inp out@@ -361,6 +378,8 @@ runInstr i@(InstrWithVarAnns _ _i1) r = runInstrImpl runInstr i r runInstr i@Nop r = runInstrImpl runInstr i r runInstr i@(Nested _) r = runInstrImpl runInstr i r+runInstr i@(DocGroup _ _i1) r = runInstrImpl runInstr i r+runInstr i@(Fn _ _ _i1) r = runInstrImpl runInstr i r runInstr i r = do rs <- isRemainingSteps <$> getInterpreterState if rs == 0@@ -373,7 +392,7 @@ runInstrNoGas = runInstrImpl runInstrNoGas -- | Function to interpret Michelson instruction(s) against given stack.-runInstrImpl :: EvalM m => InstrRunner m -> InstrRunner m+runInstrImpl :: forall m. EvalM m => InstrRunner m -> InstrRunner m runInstrImpl runner (Seq i1 i2) r = runner i1 r >>= \r' -> runner i2 r' runInstrImpl runner (WithLoc _ i) r = runner i r runInstrImpl runner (InstrWithNotes (_ :: Proxy rest) notes instr) inp = do@@ -401,11 +420,13 @@ runInstrImpl runner (Ext nop) r = r <$ interpretExt runner (SomeItStack nop r) runInstrImpl runner (Nested sq) r = runner sq r runInstrImpl runner (DocGroup _ sq) r = runInstrImpl runner sq r+runInstrImpl runner (Fn _ _ i) r = runner i r runInstrImpl _ DROP (_ :& r) = pure $ r-runInstrImpl runner (DROPN s) stack =- case s of- SZ -> pure stack- SS s' -> case stack of+runInstrImpl runner (DROPN n) stack =+ case n of+ Zero -> pure stack+ Succ s' -> case stack of+ (_ :& r) -> runInstrImpl runner (DROPN s') r -- Note: we intentionally do not use `runner` to recursively -- interpret `DROPN` here. -- All these recursive calls together correspond to a single@@ -413,35 +434,38 @@ -- This recursion is implementation detail of `DROPN`. -- The same reasoning applies to other instructions parameterized -- by a natural number like 'DIPN'.- (_ :& r) -> runInstrImpl runner (DROPN s') r-runInstrImpl _ DUP (a :& r) = pure $ a :& a :& r-runInstrImpl _ (DUPN nSing) stack = pure $ go nSing stack+runInstrImpl _ DUP (stkEl :& r) = do+ -- If we're duplicating a big_map, or a value containing big_map(s), we need to generate new big_map ID(s).+ duplicateStkEl <- traverseOf seValueL assignBigMapIds' stkEl+ pure $ duplicateStkEl :& stkEl :& r+runInstrImpl _ (DUPN s) stack = go s stack where go :: forall (n :: Peano) inp out a. ConstraintDUPN n inp out a- => Sing n -> Rec StkEl inp -> Rec StkEl out- go = curry \case- -- Discard variable annotations. This is consistent with tezos-client.- (SS SZ, i@(StkEl a _ n :& _)) -> StkEl a U.noAnn n :& i- (SS s@(SS _), b :& r) -> case go s r of+ => PeanoNatural n -> Rec StkEl inp -> m (Rec StkEl out)+ go (Succ Zero) stk@(stkEl :& _) = do+ -- If we're duplicating a big_map, or a value containing big_map(s), we need to generate new big_map ID(s).+ duplicateStkEl <- traverseOf seValueL assignBigMapIds' stkEl+ -- Discard variable annotations. This is consistent with tezos-client.+ pure $ (duplicateStkEl & seVarAnnL .~ U.noAnn) :& stk+ go (Succ n@(Succ _)) (b :& r) =+ go n r <&> \case (a :& resTail) -> a :& b :& resTail runInstrImpl _ SWAP (a :& b :& r) = pure $ b :& a :& r-runInstrImpl _ (DIG nSing0) input0 =- pure $ go nSing0 input0+runInstrImpl _ (DIG s) input0 =+ pure $ go s input0 where go :: forall (n :: Peano) inp out a. ConstraintDIG n inp out a- => Sing n -> Rec StkEl inp -> Rec StkEl out- go = curry \case- (SZ, stack) -> stack- (SS nSing, b :& r) -> case go nSing r of- (a :& resTail) -> a :& b :& resTail-runInstrImpl _ (DUG nSing0) input0 =- pure $ go nSing0 input0+ => PeanoNatural n -> Rec StkEl inp -> Rec StkEl out+ go Zero stack = stack+ go (Succ n') (b :& r) = case go n' r of+ (a :& resTail) -> a :& b :& resTail+runInstrImpl _ (DUG s) input0 =+ pure $ go s input0 where go :: forall (n :: Peano) inp out a. ConstraintDUG n inp out a- => Sing n -> Rec StkEl inp -> Rec StkEl out- go = curry \case- (SZ, stack) -> stack- (SS s', a :& b :& r) -> b :& go s' (a :& r)+ => PeanoNatural n -> Rec StkEl inp -> Rec StkEl out+ go Zero stack = stack+ go (Succ n') (a :& b :& r) = b :& go n' (a :& r) runInstrImpl _ SOME ((seValue -> a) :& r) = withValueTypeSanity a $ pure $ starNotesStkEl (VOption (Just a)) :& r@@ -455,28 +479,30 @@ runInstrImpl _ NEVER inp = case inp of {} runInstrImpl _ (AnnPAIR{}) ((StkEl a _ _) :& (StkEl b _ _) :& r) = pure $ starNotesStkEl (VPair (a, b)) :& r-runInstrImpl _ (PAIRN nSing) stack = pure $ go nSing stack+runInstrImpl _ (AnnUNPAIR{}) ((StkEl (VPair (a, b)) _ _) :& r) =+ pure $ starNotesStkEl a :& starNotesStkEl b :& r+runInstrImpl _ (PAIRN s) stack = pure $ go s stack where- go :: forall n inp. ConstraintPairN n inp => Sing n -> Rec StkEl inp -> Rec StkEl (PairN n inp)- go (SS (SS SZ)) (StkEl a _ _ :& StkEl b _ _ :& r) =+ go :: forall n inp. ConstraintPairN n inp => PeanoNatural n -> Rec StkEl inp -> Rec StkEl (PairN n inp)+ go (Succ (Succ Zero)) (StkEl a _ _ :& StkEl b _ _ :& r) = -- if n=2 starNotesStkEl (VPair (a, b)) :& r- go (SS n@(SS (SS _))) (StkEl a _ _ :& r@(_ :& _ :& _)) =+ go (Succ n@(Succ (Succ _))) (StkEl a _ _ :& r@(_ :& _ :& _)) = -- if n>2 case go n r of StkEl combed _ _ :& r' -> starNotesStkEl (VPair (a, combed)) :& r'-runInstrImpl _ (UNPAIRN nSing) (StkEl pair0 _ pairNotes0 :& r) = do- pure $ go nSing pair0 pairNotes0 <+> r+runInstrImpl _ (UNPAIRN s) (StkEl pair0 _ pairNotes0 :& r) = do+ pure $ go s pair0 pairNotes0 <+> r where go :: forall n pair. ConstraintUnpairN n pair- => Sing n -> Value pair -> Notes pair+ => PeanoNatural n -> Value pair -> Notes pair -> Rec StkEl (UnpairN n pair) go n pair pairNotes = case (n, pair, pairNotes) of -- if n=2- (SS (SS SZ), VPair (a, b), NTPair _ aFieldAnn bFieldAnn _ _ aNotes bNotes) ->+ (Succ (Succ Zero), VPair (a, b), NTPair _ aFieldAnn bFieldAnn _ _ aNotes bNotes) -> -- @UNPAIR n@ converts field annotations into var annotations. -- -- > /* [ @pair pair (int %aa) (int %bb) (int %cc) (int %dd) ] */ ;@@ -492,11 +518,11 @@ :& StkEl b (U.convAnn @U.FieldTag @U.VarTag bFieldAnn) bNotes :& RNil -- if n>2- (SS n'@(SS (SS _)), VPair (a, b@(VPair _)), NTPair _ aFieldAnn _ _ _ aNotes bNotes) ->+ (Succ n'@(Succ (Succ _)), VPair (a, b@(VPair _)), NTPair _ aFieldAnn _ _ _ aNotes bNotes) -> StkEl a (U.convAnn @U.FieldTag @U.VarTag aFieldAnn) aNotes :& go n' b bNotes-runInstrImpl _ (AnnCAR _) (StkEl (VPair (a, _b)) _ _ :& r) = pure $ starNotesStkEl a :& r-runInstrImpl _ (AnnCDR _) (StkEl (VPair (_a, b)) _ _ :& r) = pure $ starNotesStkEl b :& r+runInstrImpl _ (AnnCAR _ _) (StkEl (VPair (a, _b)) _ _ :& r) = pure $ starNotesStkEl a :& r+runInstrImpl _ (AnnCDR _ _) (StkEl (VPair (_a, b)) _ _ :& r) = pure $ starNotesStkEl b :& r runInstrImpl _ (AnnLEFT nt nf1 nf2) ((StkEl a _ na) :& r) = withValueTypeSanity a $ pure $ StkEl (VOr $ Left a) U.noAnn (NTOr nt nf1 nf2 na starNotes) :& r@@ -515,7 +541,9 @@ runInstrImpl _ SIZE (a :& r) = pure $ starNotesStkEl (VNat $ (fromInteger . toInteger) $ evalSize $ seValue a) :& r runInstrImpl _ EMPTY_SET r = pure $ starNotesStkEl (VSet Set.empty) :& r runInstrImpl _ EMPTY_MAP r = pure $ starNotesStkEl (VMap Map.empty) :& r-runInstrImpl _ EMPTY_BIG_MAP r = pure $ starNotesStkEl (VBigMap Map.empty) :& r+runInstrImpl _ EMPTY_BIG_MAP r = do+ bigMap <- assignBigMapIds' $ VBigMap Nothing Map.empty+ pure $ starNotesStkEl bigMap :& r runInstrImpl runner (MAP (code :: Instr (MapOpInp c ': s) (b ': s))) (StkEl a vn n :& r) = do -- Evaluation must preserve all stack modifications that @MAP@'s does. (newStack, newList) <- foldlM (\(curStack, curList) (val :: StkEl (MapOpInp c)) -> do@@ -532,27 +560,27 @@ (Nothing, _) -> pure r runInstrImpl _ MEM (a :& b :& r) = pure $ starNotesStkEl (VBool (evalMem (seValue a) (seValue b))) :& r runInstrImpl _ GET (a :& b :& r) = pure $ starNotesStkEl (VOption (evalGet (seValue a) (seValue b))) :& r-runInstrImpl _ (GETN index0) (StkEl pair _ _ :& r) = do- pure $ starNotesStkEl (go index0 pair) :& r+runInstrImpl _ (GETN s) (StkEl pair _ _ :& r) = do+ pure $ starNotesStkEl (go s pair) :& r where go :: forall ix a. ConstraintGetN ix a- => Sing ix -> Value a+ => PeanoNatural ix -> Value a -> Value (GetN ix a)- go SZ a = a- go (SS SZ) (VPair (left, _)) = left- go (SS (SS n')) (VPair (_, right)) = go n' right+ go Zero a = a+ go (Succ Zero) (VPair (left, _)) = left+ go (Succ (Succ n')) (VPair (_, right)) = go n' right runInstrImpl _ UPDATE (a :& b :& StkEl c _ _ :& r) = pure $ starNotesStkEl (evalUpd (seValue a) (seValue b) c) :& r-runInstrImpl _ (UPDATEN index0) (StkEl (val :: Value val) _ _ :& StkEl pair _ _ :& r) = do- pure $ starNotesStkEl (go index0 pair) :& r+runInstrImpl _ (UPDATEN s) (StkEl (val :: Value val) _ _ :& StkEl pair _ _ :& r) = do+ pure $ starNotesStkEl (go s pair) :& r where go :: forall ix pair. ConstraintUpdateN ix pair- => Sing ix -> Value pair -> Value (UpdateN ix val pair)- go SZ _ = val- go (SS SZ) (VPair (_, right)) = VPair (val, right)- go (SS (SS n')) (VPair (left, right)) = VPair (left, go n' right)+ => PeanoNatural ix -> Value pair -> Value (UpdateN ix val pair)+ go Zero _ = val+ go (Succ Zero) (VPair (_, right)) = VPair (val, right)+ go (Succ (Succ n')) (VPair (left, right)) = VPair (left, go n' right) runInstrImpl _ GET_AND_UPDATE (StkEl key _ _ :& StkEl valMb _ _ :& StkEl collection _ _ :& r) = pure $ starNotesStkEl (VOption (evalGet key collection))@@ -582,8 +610,8 @@ pure $ a :& res runInstrImpl runner (DIPN s i) stack = case s of- SZ -> runner i stack- SS s' -> case stack of+ Zero -> runner i stack+ Succ s' -> case stack of (a :& r) -> (a :&) <$> runInstrImpl runner (DIPN s' i) r runInstrImpl _ FAILWITH (a :& _) = throwError $ MichelsonFailedWith (seValue a) runInstrImpl _ CAST (StkEl a _ _ :& r) = pure $ starNotesStkEl a :& r@@ -750,7 +778,28 @@ runInstrImpl _ SELF_ADDRESS r = do ContractEnv{..} <- ask pure $ starNotesStkEl (VAddress $ EpAddress ceSelf DefEpName) :& r-+runInstrImpl _ TICKET (StkEl dat _ _ :& StkEl (VNat am) _ _ :& r) = do+ ContractEnv{..} <- ask+ pure $ starNotesStkEl (VTicket ceSelf dat am) :& r+runInstrImpl _ READ_TICKET (te@(StkEl (VTicket addr dat am) _ _) :& r) = do+ pure $+ starNotesStkEl+ (VPair (VAddress (EpAddress addr DefEpName), (VPair (dat, VNat am))))+ :& te :& r+runInstrImpl _ SPLIT_TICKET+ (StkEl tv@(VTicket addr dat am) _ _ :&+ StkEl (VPair (VNat am1, VNat am2)) _ _ :& r) = do+ let result = withValueTypeSanity tv $ VOption do+ guard (am1 + am2 == am)+ return $ VPair (VTicket addr dat am1, VTicket addr dat am2)+ pure $ starNotesStkEl result :& r+runInstrImpl _ JOIN_TICKETS+ (StkEl (VPair (tv1@(VTicket addr1 dat1 am1), VTicket addr2 dat2 am2)) _ _ :& r) = do+ let result = withValueTypeSanity tv1 $ VOption do+ guard (addr1 == addr2)+ guard (dat1 == dat2)+ return $ VTicket addr1 dat1 (am1 + am2)+ pure $ starNotesStkEl result :& r -- | Evaluates an arithmetic operation and either fails or proceeds. runArithOp@@ -771,7 +820,7 @@ runUnpack bs = -- TODO [TM-80] Gas consumption here should depend on unpacked data size -- and size of resulting expression, errors would also spend some (all equally).- -- Fortunatelly, the inner decoding logic does not need to know anything about gas use.+ -- Fortunately, the inner decoding logic does not need to know anything about gas use. unpackValue' bs createOrigOp@@ -810,6 +859,7 @@ interpretExt _ (SomeItStack T.DOC_ITEM{} _) = pass interpretExt _ (SomeItStack T.COMMENT_ITEM{} _) = pass+interpretExt _ (SomeItStack T.STACKTYPE{} _) = pass -- | Access given stack reference (in CPS style). withStackElem@@ -823,10 +873,27 @@ where loop :: forall s (n :: Peano). (LongerThan s n)- => (Rec StkEl s, Sing n) -> a+ => (Rec StkEl s, PeanoNatural n) -> a loop = \case- (e :& _, SZ) -> cont e- (_ :& es, SS n) -> loop (es, n)+ (e :& _, Zero) -> cont e+ (_ :& es, Succ n) -> loop (es, n) +assignBigMapIds' :: EvalM m => Value t -> m (Value t)+assignBigMapIds' val = do+ bigMapCounter0 <- view isBigMapCounterL <$> getInterpreterState+ let (storageWithIds, bigMapCounter1) = runState (assignBigMapIds val) bigMapCounter0+ modifyInterpreterState (set isBigMapCounterL bigMapCounter1)+ pure storageWithIds++-- | All big_maps stored in a chain have a globally unique ID.+--+-- We use this function to assign a new ID whenever a big_map is created.+assignBigMapIds :: MonadState BigMapCounter m => Value t -> m (Value t)+assignBigMapIds =+ dfsTraverseValue \case+ VBigMap _ vBigMap -> do+ bigMapId <- bigMapCounter <<+= 1+ pure $ VBigMap (Just bigMapId) vBigMap+ v -> pure v+ (deriveGADTNFData ''MichelsonFailed)-makeLensesFor [("isMorleyLogs", "isMorleyLogsL")] ''InterpreterState
src/Michelson/Interpret/Pack.hs view
@@ -6,588 +6,39 @@ -- -- This is nearly symmetric to adjacent Unpack.hs module. module Michelson.Interpret.Pack- ( packCode'- , packT'- , packValue+ ( packValue , packValue' , packValuePrefix- -- * Serializers used in morley-client- , encodeValue'- , encodeValue- , packNotedT'- -- * Internals- , encodeIntPayload- , encodeKeyHashRaw- , encodeEpAddress+ , toBinary+ , toBinary' ) where import Prelude hiding (EQ, GT, LT) -import qualified Data.Binary.Put as Bi-import qualified Data.ByteArray as ByteArray-import qualified Data.ByteString.Lazy as LBS-import qualified Data.Map as Map-import Data.Singletons (Sing, demote)-import Data.Vinyl (Rec(..))-import Util.Type (type (++))--import Michelson.Interpret.Utils-import Michelson.Text import Michelson.Typed-import Michelson.Untyped.Annotation- (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)-import qualified Tezos.Crypto.BLS12381 as BLS-import qualified Tezos.Crypto.Ed25519 as Ed25519-import qualified Tezos.Crypto.P256 as P256-import qualified Tezos.Crypto.Secp256k1 as Secp256k1-import Util.Peano (peanoValSing)+import Morley.Micheline.Binary (encodeExpression, encodeExpression')+import Morley.Micheline.Class (ToExpression(..)) --- | Prefix prepended to the binary representation of a value.-packValuePrefix :: IsString s => s-packValuePrefix = "\x05"+-- | Generic serializer.+toBinary :: ToExpression a => a -> LByteString+toBinary = encodeExpression . toExpression +-- | Same as 'toBinary', for strict bytestring.+toBinary' :: ToExpression a => a -> ByteString+toBinary' = encodeExpression' . toExpression+ -- | Serialize a value given to @PACK@ instruction. packValue :: PackedValScope t => Value t -> LByteString-packValue x = packValuePrefix <> encodeValue x+packValue x =+ let uval = untypeValueHashable x+ in packValuePrefix <> (encodeExpression $ toExpression uval) -- | Same as 'packValue', for strict bytestring. packValue' :: PackedValScope t => Value t -> ByteString-packValue' = LBS.toStrict . packValue--encodeValue' :: (SingI t, HasNoOp t) => Value t -> ByteString-encodeValue' = LBS.toStrict . encodeValue--packT' :: forall (t :: T). SingI t => ByteString-packT' = LBS.toStrict $ encodeT' @t--packCode' :: Instr inp out -> ByteString-packCode' = LBS.toStrict . encodeInstrs---- | Generic serializer.------ We don't require @HasNoBigMap@ constraint here since the big_map serialization--- is only prohibited in @PACK@ instructions, however, we still want to be able to--- serialize big_map e.g. in order to transform typed value to low-level Micheline--- representation.--- TODO: Serialize chain operations properly as well since they actually also have--- byte representation.-encodeValue :: forall t. (SingI t, HasNoOp t) => Value t -> LByteString-encodeValue val = case (val, sing @t) of- (VKey s, _) -> encodeBytes' $ case s of- PublicKeyEd25519 pk -> "\x00" <> Ed25519.publicKeyToBytes pk- PublicKeySecp256k1 pk -> "\x01" <> Secp256k1.publicKeyToBytes pk- PublicKeyP256 pk -> "\x02" <> P256.publicKeyToBytes pk- (VUnit, _) -> "\x03\x0b"- (VSignature x, _) -> encodeBytes' $ signatureToBytes x- (VChainId x, _) ->- encodeBytes' $ ByteArray.convert (unChainId x)- (VOption (Just x), STOption _) -> "\x05\x09" <> encodeValue x- (VOption Nothing, _) -> "\x03\x06"- (VList xs, STList _) -> encodeList encodeValue xs- (VSet xs, (STSet (st :: Sing st))) -> case checkOpPresence st of- OpAbsent -> encodeList encodeValue (toList xs)- (VContract addr sepc, _) -> encodeEpAddress $ EpAddress addr (sepcName sepc)- (VPair (v1, v2), STPair l _) ->- case checkOpPresence l of- OpAbsent -> "\x07\x07" <> encodeValue v1 <> encodeValue v2- (VOr (Left v), STOr l _) ->- case checkOpPresence l of- OpAbsent -> "\x05\x05" <> encodeValue v- (VOr (Right v), STOr l _) ->- case checkOpPresence l of- OpAbsent-> "\x05\x08" <> encodeValue v- (VLam lam, _) -> encodeInstrs $ rfAnyInstr lam- (VMap m, STMap sk _) -> case checkOpPresence sk of- OpAbsent -> encodeMap m- (VBigMap m, STBigMap sk _) -> case checkOpPresence sk of- OpAbsent -> encodeMap m- (VInt x, STInt) -> encodeNumeric x- (VNat x, STNat) -> encodeNumeric x- (VString text, STString) -> encodeString text- (VBytes bytes, STBytes) -> encodeBytes' bytes- (VMutez x, STMutez) -> encodeNumeric (unMutez x)- (VBool True, STBool) -> "\x03\x0a"- (VBool False, STBool) -> "\x03\x03"- (VKeyHash kh, STKeyHash) -> encodeBytes $ encodeKeyHashRaw kh- (VBls12381Fr v, STBls12381Fr) -> encodeBytes' $ BLS.toMichelsonBytes v- (VBls12381G1 v, STBls12381G1) -> encodeBytes' $ BLS.toMichelsonBytes v- (VBls12381G2 v, STBls12381G2) -> encodeBytes' $ BLS.toMichelsonBytes v- (VTimestamp x, STTimestamp) -> encodeNumeric (timestampToSeconds @Integer x)- (VAddress addr, STAddress) -> encodeEpAddress addr--encodeLength :: Int -> LByteString-encodeLength = Bi.runPut . Bi.putWord32be . fromIntegral---- | Lift encoded list content to an entire encoded list.-encodeAsList :: LByteString -> LByteString-encodeAsList bs = encodeLength (length bs) <> bs---- | Encode a list-like structure.-encodeList :: (a -> LByteString) -> [a] -> LByteString-encodeList encodeElem l = "\x02" <> encodeAsList (LBS.concat $ map encodeElem l)---- | Encode a text.-encodeString :: MText -> LByteString-encodeString text = "\x01" <> encodeAsList (encodeUtf8 $ unMText text)---- | Encode some raw data.-encodeBytes :: LByteString -> LByteString-encodeBytes bs =- "\x0a" <> encodeAsList bs---- | Version of 'encodeBytes' that accepts a strict bytestring.-encodeBytes' :: ByteString -> LByteString-encodeBytes' = encodeBytes . LBS.fromStrict--encodeEpName :: EpName -> LByteString-encodeEpName = encodeUtf8 . unAnnotation . epNameToRefAnn . canonicalize- where- canonicalize :: EpName -> EpName- canonicalize (EpNameUnsafe "default") = DefEpName- canonicalize epName = epName---- | Encode some map.-encodeMap :: (SingI v, HasNoOp v, SingI k, HasNoOp k) => Map (Value k) (Value v) -> LByteString-encodeMap m =- encodeList (\(k, v) -> "\x07\x04" <> encodeValue k <> encodeValue v) (Map.toList m)--encodeKeyHashRaw :: KeyHash -> LByteString-encodeKeyHashRaw kh = (<> LBS.fromStrict (khBytes kh)) $- case khTag kh of- KeyHashEd25519 -> "\x00"- KeyHashSecp256k1 -> "\x01"- KeyHashP256 -> "\x02"--encodeAddress :: Address -> LByteString-encodeAddress = \case- KeyAddress keyHash ->- "\x00" <> (encodeKeyHashRaw keyHash)- ContractAddress (ContractHash address) ->- "\x01" <> LBS.fromStrict address <> "\x00"--encodeEpAddress :: EpAddress -> LByteString-encodeEpAddress (EpAddress addr epName) =- encodeBytes $ encodeAddress addr <> encodeEpName epName---- | Encode contents of a given number.-encodeIntPayload :: Integer -> LByteString-encodeIntPayload = LBS.pack . toList . encodeZarithNumber---- | Encode an int-like value.-encodeNumeric :: Integral i => i -> LByteString-encodeNumeric i = "\x00" <> encodeIntPayload (fromIntegral i)---- | Encode a code block.-encodeInstrs :: Instr inp out -> LByteString-encodeInstrs = encodeList id . one . encodeInstr---- | Encode an instruction.-encodeInstr :: forall inp out. Instr inp out -> LByteString-encodeInstr = \case- WithLoc _ i ->- encodeInstr i- InstrWithNotes proxy notes instr ->- encodeNotedInstr proxy instr notes []- InstrWithVarNotes varNotes a -> case a of- AnnLEFT{} | _ :: Proxy ('TOr l r ': s) <- Proxy @out ->- encodeVarNotedInstr a varNotes (encodeT' @r)- AnnRIGHT{} | _ :: Proxy ('TOr l r ': s) <- Proxy @out ->- encodeVarNotedInstr a varNotes (encodeT' @l)- _ -> encodeVarNotedInstr a varNotes ""- InstrWithVarAnns _ a ->- encodeInstr a- FrameInstr _ i ->- encodeInstr i- Seq a b ->- encodeInstr a <> encodeInstr b- Nop ->- mempty- Nested i ->- encodeInstrs i- DocGroup _ i ->- encodeInstrs i- Ext _ ->- ""- DROP ->- "\x03\x20"- DROPN s ->- "\x05\x20" <> encodeNumeric (peanoValSing s)- DUP ->- "\x03\x21"- DUPN s ->- "\x05\x21" <> encodeNumeric (peanoValSing s)- SWAP ->- "\x03\x4c"- DIG s ->- "\x05\x70" <> encodeNumeric (peanoValSing s)- DUG s ->- "\x05\x71" <> encodeNumeric (peanoValSing s)- PUSH (a :: Value t) ->- "\x07\x43" <> encodeT' @t <> encodeValue a- SOME ->- "\x03\x46"- NONE | _ :: Proxy ('TOption t ': s) <- Proxy @out ->- "\x05\x3e" <> encodeT' @t- UNIT ->- "\x03\x4f"- IF_NONE a b ->- "\x07\x2f" <> encodeInstrs a <> encodeInstrs b- AnnPAIR tn fn1 fn2 ->- encodeWithAnns [tn] [fn1, fn2] [] "\x03\x42"- PAIRN n ->- "\x05\x42" <> encodeNumeric (peanoValSing n)- UNPAIRN n ->- "\x05\x7a" <> encodeNumeric (peanoValSing n)- (AnnCAR fn) ->- encodeWithAnns [] [fn] [] "\x03\x16"- (AnnCDR fn) ->- encodeWithAnns [] [fn] [] "\x03\x17"- (AnnLEFT tn fn1 fn2) | _ :: Proxy ('TOr l r ': s) <- Proxy @out ->- encodeWithAnns [tn] [fn1, fn2] [] $ "\x05\x33" <> encodeT' @r- (AnnRIGHT tn fn1 fn2) | _ :: Proxy ('TOr l r ': s) <- Proxy @out ->- encodeWithAnns [tn] [fn1, fn2] [] $ "\x05\x44" <> encodeT' @l- IF_LEFT a b ->- "\x07\x2e" <> encodeInstrs a <> encodeInstrs b- NIL | _ :: Proxy ('TList t ': s) <- Proxy @out ->- "\x05\x3d" <> encodeT' @t- CONS ->- "\x03\x1b"- IF_CONS a b ->- "\x07\x2d" <> encodeInstrs a <> encodeInstrs b- SIZE ->- "\x03\x45"- EMPTY_SET | _ :: Proxy ('TSet t ': s) <- Proxy @out ->- "\x05\x24" <> encodeT' @t- EMPTY_MAP | _ :: Proxy ('TMap k v ': s) <- Proxy @out ->- "\x07\x23" <> encodeT' @k <> encodeT' @v- EMPTY_BIG_MAP | _ :: Proxy ('TBigMap k v ': s) <- Proxy @out ->- "\x07\x72" <> encodeT' @k <> encodeT' @v- MAP a ->- "\x05\x38" <> encodeInstrs a- ITER a ->- "\x05\x52" <> encodeInstrs a- MEM ->- "\x03\x39"- GET ->- "\x03\x29"- GETN n ->- "\x05\x29" <> encodeNumeric (peanoValSing n)- UPDATE ->- "\x03\x50"- UPDATEN n ->- "\x05\x50" <> encodeNumeric (peanoValSing n)- GET_AND_UPDATE ->- "\x03\x8c"- IF a b ->- "\x07\x2c" <> encodeInstrs a <> encodeInstrs b- LOOP a ->- "\x05\x34" <> encodeInstrs a- LOOP_LEFT a ->- "\x05\x53" <> encodeInstrs a- LAMBDA (v :: Value ('TLambda i o)) ->- "\x09\x31" <>- encodeAsList (encodeT' @i <> encodeT' @o <> encodeValue v) <>- encodeLength 0 -- encoding of a Variable Annotation (that we don't support)- EXEC ->- "\x03\x26"- APPLY ->- "\x03\x73"- DIP a ->- "\x05\x1f" <> encodeInstrs a- DIPN s a ->- "\x07\x1f" <> encodeNumeric (peanoValSing s) <> encodeInstrs a- FAILWITH ->- "\x03\x27"- CAST | _ :: Proxy (t ': s) <- Proxy @out ->- "\x05\x57" <> encodeT' @t- RENAME ->- "\x03\x58"- PACK ->- "\x03\x0c"- UNPACK | _ :: Proxy ('TOption t ': s) <- Proxy @out ->- "\x05\x0d" <> encodeT' @t- CONCAT ->- "\x03\x1a"- CONCAT' ->- "\x03\x1a"- SLICE ->- "\x03\x6f"- ISNAT ->- "\x03\x56"- ADD ->- "\x03\x12"- SUB ->- "\x03\x4b"- MUL ->- "\x03\x3a"- EDIV ->- "\x03\x22"- ABS ->- "\x03\x11"- NEG ->- "\x03\x3b"- LSL ->- "\x03\x35"- LSR ->- "\x03\x36"- OR ->- "\x03\x41"- AND ->- "\x03\x14"- XOR ->- "\x03\x51"- NOT ->- "\x03\x3f"- COMPARE ->- "\x03\x19"- EQ ->- "\x03\x25"- NEQ ->- "\x03\x3c"- LT ->- "\x03\x37"- GT ->- "\x03\x2a"- LE ->- "\x03\x32"- GE ->- "\x03\x28"- INT ->- "\x03\x30"- SELF sepc ->- case sepcName sepc of- DefEpName -> "\x03\x49"- epName -> encodeWithAnns [] [epNameToRefAnn epName] [] "\x03\x49"- CONTRACT ns ep | _ :: Proxy ('TOption ('TContract t) ': s) <- Proxy @out ->- encodeWithAnns [] [epNameToRefAnn ep] [] $ "\x05\x55" <> encodeNotedT' @t ns- TRANSFER_TOKENS ->- "\x03\x4d"- SET_DELEGATE ->- "\x03\x4e"- CREATE_CONTRACT contract@Contract{..}- | _ :: Instr '[ 'TPair p g ] '[ 'TPair ('TList 'TOperation) g ] <- cCode ->- let contents = mapEntriesOrdered contract- (\np -> "\x05\x00" <> encodeParamNotes' @p np)- (\ng -> "\x05\x01" <> encodeNotedT' @g ng)- (\instr -> "\x05\x02" <> encodeInstrs instr)- in "\x05\x1d" <> encodeList id contents- IMPLICIT_ACCOUNT ->- "\x03\x1e"- NOW ->- "\x03\x40"- AMOUNT ->- "\x03\x13"- BALANCE ->- "\x03\x15"- VOTING_POWER ->- "\x03\x7b"- TOTAL_VOTING_POWER ->- "\x03\x7c"- CHECK_SIGNATURE ->- "\x03\x18"- SHA256 ->- "\x03\x0f"- SHA512 ->- "\x03\x10"- BLAKE2B ->- "\x03\x0e"- SHA3 ->- "\x03\x7e"- KECCAK ->- "\x03\x7d"- HASH_KEY ->- "\x03\x2b"- PAIRING_CHECK ->- "\x03\x7f"- SOURCE ->- "\x03\x47"- SENDER ->- "\x03\x48"- ADDRESS ->- "\x03\x54"- CHAIN_ID ->- "\x03\x75"- LEVEL ->- "\x03\x76"- SELF_ADDRESS ->- "\x03\x77"- NEVER ->- "\x03\x79"----- | Iff there are non-empty annotations it increments the value's tag and--- appends the encoded annotations.-encodeWithAnns :: [TypeAnn] -> [FieldAnn] -> [VarAnn] -> LByteString -> LByteString-encodeWithAnns tns fns vns encodedInput- | null encodedInput = encodedInput- | isNoAnnSet annSet = encodedInput- | otherwise = inputIncrem <> encodedAnns- where- annSet = fullAnnSet tns fns vns- encodedAnns = encodeAsList . encodeUtf8 $ show @Text annSet- inputIncrem = (1 + LBS.head encodedInput) `LBS.cons` LBS.tail encodedInput---- | Encode an instruction with variable annotations-encodeVarNotedInstr :: Instr inp out -> NonEmpty VarAnn -> LByteString -> LByteString-encodeVarNotedInstr i vns'@(toList -> vns) encodedType = case i of- InstrWithNotes proxy n a -> encodeNotedInstr proxy a n vns- InstrWithVarAnns _ a -> encodeInstr $ InstrWithVarNotes vns' a- -- AnnPAIR, AnnCAR, AnnCDR and AnnLEFT, AnnRIGHT are checked here because- -- their cases on `encodeInstr` increment them to \x04 and to \x05 respectively- -- when they have a field annotation, but they would also get increment due to- -- variable annotations, resulting in incorrect \x05 and \x06 codes respectively.- AnnPAIR tn fn1 fn2 -> encodeWithAnns [tn] [fn1, fn2] vns "\x03\x42"- AnnCAR fn -> encodeWithAnns [] [fn] vns "\x03\x16"- AnnCDR fn -> encodeWithAnns [] [fn] vns "\x03\x17"- AnnLEFT tn fn1 fn2 -> encodeWithAnns [tn] [fn1, fn2] vns $ "\x05\x33" <> encodedType- AnnRIGHT tn fn1 fn2 -> encodeWithAnns [tn] [fn1, fn2] vns $ "\x05\x44" <> encodedType- _ -> encodeWithAnns [] [] vns $ encodeInstr i---- | Encode an instruction with Annotations-encodeNotedInstr- :: forall inp out topElems rest.- out ~ (topElems ++ rest)- => Proxy rest -> Instr inp out -> Rec Notes topElems -> [VarAnn] -> LByteString-encodeNotedInstr proxy instr notes vns = case (instr, Proxy @out, notes) of- (WithLoc _ instr', _, _) ->- encodeNotedInstr proxy instr' notes vns- (SOME, _, NTOption tn _ns :& _) ->- encodeWithAnns [tn] [] vns $ encodeInstr instr- (NONE, _ :: Proxy ('TOption t ': s), NTOption tn ns :& _) ->- encodeWithAnns [tn] [] vns $ "\x05\x3e" <> encodeNotedT' @t ns- (UNIT, _, NTUnit tn :& _) ->- encodeWithAnns [tn] [] vns $ encodeInstr instr- (NIL, _ :: Proxy ('TList t ': s), NTList tn ns :& _) ->- encodeWithAnns [tn] [] vns $ "\x05\x3d" <> encodeNotedT' @t ns- (EMPTY_SET, _ :: Proxy ('TSet t ': s), NTSet tn ns :& _) ->- encodeWithAnns [tn] [] vns $ "\x05\x24" <> encodeNotedT' @t ns- (EMPTY_MAP, _ :: Proxy ('TMap k v ': s), NTMap tn1 nk ns :& _) ->- encodeWithAnns [tn1] [] vns $- "\x07\x23" <> encodeNotedT' @k nk <> encodeNotedT' @v ns- (EMPTY_BIG_MAP, _ :: Proxy ('TBigMap k v ': s), NTBigMap tn1 nk ns :& _) ->- encodeWithAnns [tn1] [] vns $- "\x07\x72" <> encodeNotedT' @k nk <> encodeNotedT' @v ns- (PUSH (v :: Value t), _, tn :& _) ->- "\x07\x43" <> encodeNotedT' @t tn <> encodeValue v- (LAMBDA (v :: Value ('TLambda i o)), _, NTLambda _tn ns1 ns2 :& _) ->- "\x09\x31" <>- encodeAsList (encodeNotedT' @i ns1 <> encodeNotedT' @o ns2 <> encodeValue v) <>- encodeLength 0 -- encoding of a Variable Annotation (that we don't support)- (CAST, _ :: Proxy (t ': s), tn :& _) ->- "\x05\x57" <> encodeNotedT' @t tn- (UNPACK, _ :: Proxy ('TOption t ': s), NTOption tn ns :& _) ->- encodeWithAnns [tn] [] vns $ "\x05\x0d" <> encodeNotedT' @t ns- -- NOTE: `CONTRACT` may be part of an `InstrWithNotes` with `NTOption`, but is- -- taken care of in `encodeInstr` anyway (because it contains the note itself)- _ -> encodeInstr instr--packNotedT' :: forall (t :: T). SingI t => Notes t -> ByteString-packNotedT' = LBS.toStrict . encodeNotedT'--encodeNotedT' :: forall (t :: T). SingI t => Notes t -> LByteString-encodeNotedT' = encodeNotedST (sing @t) noAnn--encodeParamNotes' ::- forall (t :: T). SingI t => ParamNotes t -> LByteString-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.-encodeNotedST :: Sing t -> FieldAnn -> Notes t -> LByteString-encodeNotedST st fn n = case (st, n) of- (STInt, NTInt tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STNat, NTNat tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STString, NTString tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STBytes, NTBytes tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STMutez, NTMutez tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STBool, NTBool tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STKeyHash, NTKeyHash tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STBls12381Fr, NTBls12381Fr tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STBls12381G1, NTBls12381G1 tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STBls12381G2, NTBls12381G2 tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STTimestamp, NTTimestamp tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)- (STAddress, NTAddress tn) ->- encodeWithAnns [tn] [fn] [] $ encodeT (fromSingT st)-- (STKey, NTKey tn) ->- encodeWithAnns [tn] [fn] [] $ "\x03\x5c"- (STUnit, NTUnit tn) ->- encodeWithAnns [tn] [fn] [] $ "\x03\x6c"- (STNever, NTNever tn) ->- encodeWithAnns [tn] [fn] [] $ "\x03\x78"- (STSignature, NTSignature tn) ->- encodeWithAnns [tn] [fn] [] $ "\x03\x67"- (STChainId, NTChainId tn) ->- encodeWithAnns [tn] [fn] [] $ "\x03\x74"- (STOption a, NTOption tn ns) ->- encodeWithAnns [tn] [fn] [] $ "\x05\x63" <> encodeNotedST a noAnn ns- (STList a, NTList tn ns) ->- encodeWithAnns [tn] [fn] [] $ "\x05\x5f" <> encodeNotedST a noAnn ns- (STSet a, NTSet tn ns) ->- encodeWithAnns [tn] [fn] [] $ "\x05\x66" <> encodeNotedST a noAnn ns- (STOperation, NTOperation tn) ->- encodeWithAnns [tn] [fn] [] $ "\x03\x6d"- (STContract a, NTContract tn ns) ->- encodeWithAnns [tn] [fn] [] $ "\x05\x5a" <> encodeNotedST a noAnn ns- (STPair a b, NTPair tn fn1 fn2 _vn1 _vn2 ns1 ns2) ->- encodeWithAnns [tn] [fn] [] $- "\x07\x65" <> encodeNotedST a fn1 ns1 <> encodeNotedST b fn2 ns2- (STOr a b, NTOr tn fn1 fn2 ns1 ns2) ->- encodeWithAnns [tn] [fn] [] $- "\x07\x64" <> encodeNotedST a fn1 ns1 <> encodeNotedST b fn2 ns2- (STLambda a r, NTLambda tn ns1 ns2) ->- encodeWithAnns [tn] [fn] [] $- "\x07\x5e" <> encodeNotedST a noAnn ns1 <> encodeNotedST r noAnn ns2- (STMap k v, NTMap tn nk nv) ->- encodeWithAnns [tn] [fn] [] $- "\x07\x60" <> encodeNotedST k noAnn nk <> encodeNotedST v noAnn nv- (STBigMap k v, NTBigMap tn nk nv) ->- encodeWithAnns [tn] [fn] [] $- "\x07\x61" <> encodeNotedST k noAnn nk <> encodeNotedST v noAnn nv--encodeT :: T -> LByteString-encodeT = \case- TKey -> "\x03\x5c"- TUnit -> "\x03\x6c"- TNever -> "\x03\x78"- TSignature -> "\x03\x67"- TChainId -> "\x03\x74"- TOption t -> "\x05\x63" <> encodeT t- TList t -> "\x05\x5f" <> encodeT t- TSet t -> "\x05\x66" <> encodeT t- TOperation -> "\x03\x6d"- TContract t -> "\x05\x5a" <> encodeT t- TPair a b -> "\x07\x65" <> encodeT a <> encodeT b- TOr a b -> "\x07\x64" <> encodeT a <> encodeT b- TLambda a r -> "\x07\x5e" <> encodeT a <> encodeT r- TMap k v -> "\x07\x60" <> encodeT k <> encodeT v- TBigMap k v -> "\x07\x61" <> encodeT k <> encodeT v- TInt -> "\x03" <> "\x5b"- TNat -> "\x03" <> "\x62"- TString -> "\x03" <> "\x68"- TBytes -> "\x03" <> "\x69"- TMutez -> "\x03" <> "\x6a"- TBool -> "\x03" <> "\x59"- TKeyHash -> "\x03" <> "\x5d"- TBls12381Fr -> "\x03" <> "\x82"- TBls12381G1 -> "\x03" <> "\x80"- TBls12381G2 -> "\x03" <> "\x81"- TTimestamp -> "\x03" <> "\x6b"- TAddress -> "\x03" <> "\x6e"+packValue' x =+ let uval = untypeValueHashable x+ in packValuePrefix <> (encodeExpression' $ toExpression uval) -encodeT' :: forall (t :: T). SingI t => LByteString-encodeT' = encodeT (demote @t)+-- | Prefix prepended to the binary representation of a value.+packValuePrefix :: IsString s => s+packValuePrefix = "\x05"
src/Michelson/Interpret/Unpack.hs view
@@ -17,119 +17,25 @@ -} module Michelson.Interpret.Unpack ( UnpackError (..)- , unpackValue- , unpackValue' , unpackInstr'-- -- * Internals- , decodeContract- , decodeType+ , unpackUValue'+ , unpackValue' ) where import Prelude hiding (EQ, Ordering(..), get) -import Control.Monad.Except (throwError)-import Data.Binary (Get)-import qualified Data.Binary.Get as Get-import qualified Data.Bits as Bits import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS import Data.Constraint (Dict(..))-import Data.Default (def)-import qualified Data.Map as Map-import qualified Data.Set as Set-import Data.Singletons (Sing, SingI(..))-import Data.Typeable ((:~:)(..))-import Fmt (Buildable, Builder, fmt, hexF, padLeftF, pretty, (+|), (|+))+import Fmt (pretty) -import Michelson.Parser (Parser, ParserException(..), parseNoEnv)-import qualified Michelson.Parser.Annotations as PA-import Michelson.Text-import Michelson.TypeCheck- (HST(..), SomeHST(..), SomeInstr(..), SomeInstrOut(..), TCError(..), TypeCheckEnv(..),- TypeCheckMode(..), TypeContext(..), withWTPm)-import Michelson.TypeCheck.Helpers (ensureDistinctAsc, eqHST1)-import Michelson.TypeCheck.Instr (typeCheckList)-import Michelson.Typed (KnownT, RemFail(..), SingT(..), starNotes)+import Michelson.Typed (UnpackedValScope) import qualified Michelson.Typed as T-import Michelson.Typed.Entrypoints-import Michelson.Typed.Scope (UnpackedValScope) import Michelson.Untyped-import Tezos.Core-import Tezos.Crypto hiding (sign)-import qualified Tezos.Crypto.BLS12381 as BLS+import qualified Michelson.Untyped as U+import Morley.Micheline.Binary (eitherDecodeExpression)+import Morley.Micheline.Class (FromExpression(..)) import Util.Binary-import Util.Num -------------------------------------------------------------------------------- Helpers--------------------------------------------------------------------------------- | Alias for label attaching.-(?) :: Get a -> String -> Get a-(?) = flip Get.label-infix 0 ?---- | Displays bytes sequence.-bytesF :: [Word8] -> Builder-bytesF bs = "0x" <> foldMap (padLeftF 2 '0' . hexF) bs---- | Read a byte and match it against given value.-expectTag :: String -> Word8 -> Get ()-expectTag desc t =- Get.label desc $ do- t' <- Get.getWord8- unless (t == t') $- fail . fmt $ "Unexpected tag value (expected " +| bytesF [t] |+- ", but got " +| bytesF [t'] |+ ")"----- | Read a byte describing the primitive going further and match it against--- expected tag in the given conditions.------ Aside of context description, you have to specify number of arguments which--- given instruction accepts when written in Michelson. For instance, @PUSH@--- accepts two arguments - type and value.-expectDescTag :: HasCallStack => String -> Word16 -> Get ()-expectDescTag desc argsNum =- Get.label desc $ do- tag <- Get.getWord8- unless (tag == expected) $- fail . fmt $ "Unexpected preliminary tag: " <> bytesF [tag]- where- expected = case argsNum of- 0 -> 0x03- 1 -> 0x05- 2 -> 0x07- 3 -> 0x08- _ -> error "Bad arguments num"- -- Intermediate values of tag are also used and designate that annotations- -- are also attached to the packed data. But they are never produced by- -- @PACK@, neither @UNPACK@ seem to expect them, so for now we pretend- -- that annotations do not exist.---- | Read a byte indicating the number of arguments/annotations of--- the primitive that follows it.-decodeDescTag :: String -> Get Word8-decodeDescTag desc =- Get.label desc- Get.getWord8---- | Like 'many', but doesn't backtrack if next entry failed to parse--- yet there are some bytes to consume ahead.------ This function exists primarily for better error messages.-manyForced :: Get a -> Get [a]-manyForced decode = do- emp <- Get.isEmpty- if emp- then return []- else (:) <$> decode <*> manyForced decode--------------------------------------------------------------------------------- Michelson serialisation------------------------------------------------------------------------------ {- Implementation notes: * We need to know which exact type we unpack to.@@ -152,823 +58,27 @@ -- | Deserialize bytes into the given value. -- Suitable for @UNPACK@ operation only.-unpackValue- :: (UnpackedValScope t)- => LByteString -> Either UnpackError (T.Value t)-unpackValue = launchGet (finalizeDecoder decodeValue)---- | Like 'unpackValue', for strict byte array. unpackValue'- :: (UnpackedValScope t)+ :: forall t. (UnpackedValScope t) => ByteString -> Either UnpackError (T.Value t)-unpackValue' = unpackValue . LBS.fromStrict+unpackValue' = unpackImpl @(T.Value t)+ where+ _reallyNeedThisConstraint = Dict @(UnpackedValScope t) -- | Deserialize an instruction into the given value. unpackInstr' :: ByteString -> Either UnpackError [ExpandedOp]-unpackInstr' = launchGet (finalizeDecoder decodeOps) . LBS.fromStrict---- | Turn composable decoder into a final decoder which will be run over data.-finalizeDecoder :: Get a -> Get a-finalizeDecoder decoder =- expectTag "Packed data start" 0x05 *> decoder <* ensureEnd--decodeValue- :: forall t.- (HasCallStack, UnpackedValScope t)- => Get (T.Value t)-decodeValue = Get.label "Value" $- case sing @t of- STKey -> T.VKey <$> decodeAsBytesOrString- ( decodeWithTag "key" keyDecoders- , parsePublicKey- )- STUnit -> do- expectDescTag "Unit" 0- expectTag "Unit" 0x0B- return T.VUnit- STSignature -> T.VSignature <$> decodeAsBytesOrString- ( decodeBytesLikeMaybe "signature wrong size" mkSignature- , parseSignature- )- STChainId -> T.VChainId <$> decodeAsBytesOrString- ( decodeBytesLikeMaybe "chain_id wrong size" mkChainId- , parseChainId- )- STOption _ -> do- Get.getByteString 2 >>= \case- "\x03\x06" -> pure (T.VOption Nothing)- "\x05\x09" -> T.VOption . Just <$> decodeValue- other -> fail $ "Unknown option tag: " <> show other- STList _ -> do- decodeAsList $ T.VList <$> manyForced decodeValue- STSet (st :: Sing st) -> withComparable st $ do- decodeAsList $ do- vals <- withUnpackedValueScope @st $ manyForced decodeValue- either (fail . toString) pure $- T.VSet . Set.fromDistinctAscList <$> ensureDistinctAsc id vals-- STPair (_:: Sing lt) (r :: Sing rt) -> do- withUnpackedValueScope @rt $ do- decodeDescTag "Pair" >>= \case- 0x07 -> do- -- "Normal" pair notation, e.g. `Pair 1 2` or `Pair 1 (Pair 2 3)`- expectTag "Pair" 0x07- T.VPair ... (,) <$> decodeValue <*> decodeValue- 0x09 -> do- -- Right-combed notation, e.g. `Pair 1 2 3`- expectTag "Pair" 0x07-- -- Find out how many bytes it took to encode the pair's elements, and decode them.- elemLen <- decodeLength ? "Right-combed pair length"- val <- Get.isolate elemLen (go @lt @rt r) ? "Right-combed pair elements"-- -- Find out how many bytes it took to encode the pair's annotations - there should be no annotations.- (decodeLength ? "Right-combed pair annotations' length") >>= \case- 0 -> pass- _ -> fail "Cannot decode values with annotations"- pure val- 0x02 -> do- -- List notation, e.g. `{ 1 ; 2 ; 3 }`- elemLen <- decodeLength ? "Right-combed pair length"- Get.isolate elemLen (go @lt @rt r) ? "Right-combed pair elements"- tag -> fail . fmt $ "Unexpected preliminary tag: 0x" <> hexF tag- where- go :: forall l r. (UnpackedValScope l, UnpackedValScope r) => Sing r -> Get (T.Value ('T.TPair l r))- go singR =- case singR of- -- If there are more pairs to the right of the right-combed pair, decode them.- STPair (_ :: Sing rl) (singRR :: Sing rr) -> do- withUnpackedValueScope @rr $ do- T.VPair ... (,) <$> decodeValue @l <*> go @rl @rr singRR- _ ->- T.VPair ... (,) <$> decodeValue @l <*> decodeValue @r- STOr (_ :: Sing lt) _ ->- withUnpackedValueScope @lt $ do- expectDescTag "Or" 1- Get.getWord8 >>= \case- 0x05 -> T.VOr . Left <$> decodeValue- 0x08 -> T.VOr . Right <$> decodeValue- other -> unknownTag "or constructor" other- STLambda (_ :: Sing t1) (_ :: Sing t2) -> do- uinstr <- decodeOps- withWTPm @t2 $- withWTPm @t1 (T.VLam <$> decodeTypeCheckLam uinstr)- STMap (st :: Sing st) (_ :: Sing sv) ->- withUnpackedValueScope @st $- withComparable st $ T.VMap <$> decodeMap-- STInt -> T.VInt <$> decodeTaggedInt "Int"- STNat -> T.VNat <$> decodeTaggedInt "Nat"- STString -> do- expectTag "String" 0x01- T.VString <$> decodeString- STBytes -> do- expectTag "Bytes" 0x0a- T.VBytes <$> decodeBytes- STMutez -> do- mmutez <- mkMutez <$> decodeTaggedInt "Mutez"- maybe (fail "Negative mutez") (pure . T.VMutez) mmutez- STBool -> do- expectDescTag "Bool" 0- Get.getWord8 >>= \case- 0x0A -> pure (T.VBool True)- 0x03 -> pure (T.VBool False)- other -> unknownTag "bool" other- STKeyHash -> T.VKeyHash <$> decodeAsBytesOrString- ( decodeWithTag "key_hash" keyHashDecoders- , parseKeyHash- )- STBls12381Fr -> fmap T.VBls12381Fr $- Get.label "bls12_381_fr" $ Get.getWord8 >>= \case- 0x0A -> decodeBls12Bytes- 0x00 -> fromInteger <$> decodeInt- other -> unknownTag "bytes or int" other- STBls12381G1 -> do- expectTag "Bls12381G1 bytes" 0x0A- T.VBls12381G1 <$> decodeBls12Bytes- STBls12381G2 -> do- expectTag "Bls12381G2 bytes" 0x0A- T.VBls12381G2 <$> decodeBls12Bytes- STTimestamp -> Get.label "Timestamp" $ Get.getWord8 >>= \case- 0x00 -> do- T.VTimestamp . timestampFromSeconds <$> decodeInt- 0x01 -> do- str <- decodeString- maybe (fail $ toString $ "failed to parse timestamp from " <> unMText str)- (pure . T.VTimestamp) $ parseTimestamp $ unMText str- other -> unknownTag "int or string" other- STAddress ->- T.VAddress <$> decodeAsBytesOrString- ( decodeBytesLike "EpAddress" parseEpAddressRaw- , parseEpAddress- )- STNever -> fail $ "cannot decode to `never` type"---withUnpackedValueScope- :: forall a v m. (KnownT a, MonadFail m)- => (T.UnpackedValScope a => m v)- -> m v-withUnpackedValueScope act = case T.checkScope @(T.UnpackedValScope a) of- Right Dict -> act- _ -> fail "Unpackable value is required here"--withComparable- :: forall a v m. (MonadFail m)- => Sing a- -> (T.Comparable a => m v)- -> m v-withComparable a act = case T.getComparableProofS a of- Just Dict -> act- Nothing -> fail "Comparable type is required here"---- | Read length of something (list, string, ...).-decodeLength :: Get Int-decodeLength = Get.label "Length" $ do- len <- Get.getWord32be- -- @martoon: I'm not sure whether returning 'Int' is valid here.- -- Strictly speaking, it may be 'Word32', but there seems to be no easy way- -- to check the reference implementation on that.- -- 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.- fromIntegralChecked len- & either (fail . toString) pure- ? "Length"--decodeAsListRaw :: Get a -> Get a-decodeAsListRaw getElems = do- l <- decodeLength ? "List length"- Get.isolate l (getElems ? "List content")---- | Given decoder for list content, get a whole list decoder.-decodeAsList :: Get a -> Get a-decodeAsList getElems = do- expectTag "List" 0x02- decodeAsListRaw getElems--decodeString :: Get MText-decodeString = do- l <- decodeLength ? "String length"- ss <- replicateM l Get.getWord8 ? "String content"- ss' <- decodeUtf8' (BS.pack ss)- & either (fail . show) pure- ? "String UTF-8 decoding"- mkMText ss'- & either (fail . show) pure- ? "Michelson string validity analysis"--decodeAsBytesRaw :: (Int -> Get a) -> Get a-decodeAsBytesRaw decode = do- l <- decodeLength ? "Byte array length"- decode l--decodeAsBytesOrString :: Buildable e => (Get a, Text -> Either e a) -> Get a-decodeAsBytesOrString (bytesDecoder, strParser) =- Get.getWord8 >>= \case- 0x01 -> do- str <- decodeString- either (fail . pretty) pure $ strParser $ unMText str- 0x0A -> do- decodeAsBytesRaw $ \l ->- Get.isolate l bytesDecoder ? "Binary content"- other -> unknownTag "text or string" other---decodeBytesLikeMaybe- :: String -> (ByteString -> Maybe a) -> Get a-decodeBytesLikeMaybe onErr constructor = do- bs <- getRemainingByteStringCopy- case constructor bs of- Nothing -> fail onErr- Just res -> pure res--decodeBytes :: Get ByteString-decodeBytes =- decodeAsBytesRaw $ Get.label "Bytes payload" . getByteStringCopy--decodeBls12Bytes :: BLS.CurveObject a => Get a-decodeBls12Bytes = do- bs <- decodeBytes- BLS.fromMichelsonBytes bs- & either (fail . pretty) pure--decodeMap- :: forall k v.(UnpackedValScope k, UnpackedValScope v)- => Get $ Map (T.Value k) (T.Value v)-decodeMap = withComparable (sing @k) $ Get.label "Map" $- decodeAsList $ do- es <- manyForced $ do- expectDescTag "Elt" 2- expectTag "Elt" 0x04- (,) <$> decodeValue <*> decodeValue- either (fail . toString) pure $- Map.fromDistinctAscList <$> ensureDistinctAsc fst es---- | An integral expression always appears tagged with 0x00.--- This function reads the tag, discards it, and reads the int that follows it.-decodeTaggedInt :: (Integral i, Bits.Bits i) => String -> Get i-decodeTaggedInt label =- expectTag label 0x00 *> decodeInt---- | Read a numeric value.-decodeInt :: (Integral i, Bits.Bits i) => Get i-decodeInt = (Bits.toIntegralSized @Integer <$> loop 0 0 ? "Number")- >>= maybe (fail "Value doesn't satisfy type ranges") pure- where- loop !offset !acc = do- byte <- Get.getWord8-- let hasCont = Bits.testBit byte 7- let doCont shft = if hasCont then loop (shft + offset) else pure- let addAndCont shft bytePayload =- doCont shft $ acc + Bits.shiftL (fromIntegral bytePayload) offset-- let payload = Bits.clearBit byte 7- if offset > 0- then addAndCont 7 payload- else do- let sign = if Bits.testBit byte 6 then -1 else 1- let upayload = Bits.clearBit payload 6- (sign *) <$> addAndCont 6 upayload---- | Type check instruction occurred from a lambda.-decodeTypeCheckLam- :: forall inp out m.- (T.WellTyped inp, T.WellTyped out, MonadFail m)- => [ExpandedOp]- -> m (RemFail T.Instr '[inp] '[out])-decodeTypeCheckLam uinstr =- either tcErrToFail pure . run $ do- let inp = (starNotes, Dict, noAnn) ::& SNil- _ :/ instr' <- typeCheckList uinstr inp- case instr' of- instr ::: out' ->- case eqHST1 @out out' of- Right Refl ->- pure $ RfNormal instr- Left err ->- -- dummy types, we have no full information to build untyped- -- 'T' anyway- let tinp = Ty TUnit noAnn- tout = Ty TUnit noAnn- in throwError $- TCFailedOnInstr (LAMBDA noAnn tinp tout uinstr) (SomeHST inp) def- (Just LambdaCode) (Just err)- AnyOutInstr instr ->- return $ RfAlwaysFails instr- where- run = evaluatingState tcInitEnv . runExceptT . usingReaderT def- tcErrToFail err = fail $ "Type check failed: " +| err |+ ""- tcInitEnv =- TypeCheckEnv- { tcExtFrames = error "runInstrImpl(UNPACK): tcExtFrames touched"- --- ^ This is safe because @UNPACK@ never produces Ext instructions- , tcMode = TypeCheckPack- }--decodeInstr :: Get ExpandedInstr-decodeInstr = Get.label "Instruction" $ do- pretag <- Get.getWord8 ? "Pre instr tag"- tag <- Get.getWord8 ? "Instr tag"- case (pretag, tag) of- (0x03, 0x20) -> pure $ DROP- (0x05, 0x20) -> DROPN <$> decodeTaggedInt "'DROP n' parameter"- (0x03, 0x21) -> DUP <$> decodeNoAnn- (0x05, 0x21) -> DUPN <$> decodeNoAnn <*> (expectTag "'DUP n' parameter" 0x00 *> decodeInt)- (0x03, 0x4C) -> pure $ SWAP- (0x05, 0x70) -> DIG <$> decodeTaggedInt "'DIG n' parameter"- (0x05, 0x71) -> DUG <$> decodeTaggedInt "'DUG n' parameter"- (0x07, 0x43) -> do- (typ, val) <- decodePushVal- an <- decodeNoAnn- return $ PUSH an typ val- (0x03, 0x46) -> SOME <$> decodeNoAnn <*> decodeNoAnn- (0x05, 0x3E) -> NONE <$> decodeNoAnn <*> decodeNoAnn <*> decodeType- (0x03, 0x4F) -> UNIT <$> decodeNoAnn <*> decodeNoAnn- (0x07, 0x2F) -> IF_NONE <$> decodeOps <*> decodeOps- (0x03, 0x42) -> PAIR <$> decodeNoAnn <*> decodeNoAnn <*> decodeNoAnn <*> decodeNoAnn- (0x05, 0x42) -> do- n <- decodeTaggedInt "'PAIR n' parameter"- varAnn <- decodeNoAnn- pure $ PAIRN varAnn n- (0x05, 0x7a) -> UNPAIRN <$> decodeTaggedInt "'UNPAIR n' parameter"- (0x03, 0x16) -> CAR <$> decodeNoAnn <*> decodeNoAnn- (0x03, 0x17) -> CDR <$> decodeNoAnn <*> decodeNoAnn- (0x05, 0x33) -> LEFT <$> decodeNoAnn <*> decodeNoAnn <*> decodeNoAnn <*> decodeNoAnn- <*> decodeType- (0x05, 0x44) -> RIGHT <$> decodeNoAnn <*> decodeNoAnn <*> decodeNoAnn <*> decodeNoAnn- <*> decodeType- (0x07, 0x2E) -> IF_LEFT <$> decodeOps <*> decodeOps- (0x05, 0x3D) -> NIL <$> decodeNoAnn <*> decodeNoAnn <*> decodeType- (0x03, 0x1B) -> CONS <$> decodeNoAnn- (0x07, 0x2D) -> IF_CONS <$> decodeOps <*> decodeOps- (0x03, 0x45) -> SIZE <$> decodeNoAnn- (0x05, 0x24) -> EMPTY_SET <$> decodeNoAnn <*> decodeNoAnn <*> decodeComparable- (0x07, 0x23) -> EMPTY_MAP <$> decodeNoAnn <*> decodeNoAnn <*> decodeComparable- <*> decodeType- (0x07, 0x72) -> EMPTY_BIG_MAP <$> decodeNoAnn <*> decodeNoAnn <*> decodeComparable- <*> decodeType- (0x05, 0x38) -> MAP <$> decodeNoAnn <*> decodeOps- (0x05, 0x52) -> ITER <$> decodeOps- (0x03, 0x39) -> MEM <$> decodeNoAnn- (0x03, 0x29) -> GET <$> decodeNoAnn- (0x05, 0x29) -> GETN <$> decodeNoAnn <*> decodeTaggedInt "'GET n' parameter"- (0x03, 0x50) -> UPDATE <$> decodeNoAnn- (0x05, 0x50) -> UPDATEN <$> decodeNoAnn <*> decodeTaggedInt "'UPDATE n' parameter"- (0x03, 0x8c) -> GET_AND_UPDATE <$> decodeNoAnn- (0x07, 0x2C) -> IF <$> decodeOps <*> decodeOps- (0x05, 0x34) -> LOOP <$> decodeOps- (0x05, 0x53) -> LOOP_LEFT <$> decodeOps- (0x09, 0x31) -> do- (ti, to, ops) <- decodeAsListRaw $- (,,) <$> decodeType <*> decodeType <*> decodeOps- vAnn <- decodeVAnnDef- return $ LAMBDA vAnn ti to ops- (0x03, 0x26) -> EXEC <$> decodeNoAnn- (0x03, 0x73) -> APPLY <$> decodeNoAnn- (0x05, 0x1F) -> DIP <$> decodeOps- (0x07, 0x1F) -> DIPN <$> decodeTaggedInt "'DIP n' parameter" <*> decodeOps- (0x03, 0x27) -> pure FAILWITH- (0x05, 0x57) -> CAST <$> decodeNoAnn <*> decodeType- (0x03, 0x58) -> RENAME <$> decodeNoAnn- (0x03, 0x0C) -> PACK <$> decodeNoAnn- (0x05, 0x0D) -> UNPACK <$> decodeNoAnn <*> decodeNoAnn <*> decodeType- (0x03, 0x1A) -> CONCAT <$> decodeNoAnn- (0x03, 0x6F) -> SLICE <$> decodeNoAnn- (0x03, 0x56) -> ISNAT <$> decodeNoAnn- (0x03, 0x12) -> ADD <$> decodeNoAnn- (0x03, 0x4B) -> SUB <$> decodeNoAnn- (0x03, 0x3A) -> MUL <$> decodeNoAnn- (0x03, 0x22) -> EDIV <$> decodeNoAnn- (0x03, 0x11) -> ABS <$> decodeNoAnn- (0x03, 0x3B) -> NEG <$> decodeNoAnn- (0x03, 0x35) -> LSL <$> decodeNoAnn- (0x03, 0x36) -> LSR <$> decodeNoAnn- (0x03, 0x41) -> OR <$> decodeNoAnn- (0x03, 0x14) -> AND <$> decodeNoAnn- (0x03, 0x51) -> XOR <$> decodeNoAnn- (0x03, 0x3F) -> NOT <$> decodeNoAnn- (0x03, 0x19) -> COMPARE <$> decodeNoAnn- (0x03, 0x25) -> EQ <$> decodeNoAnn- (0x03, 0x3C) -> NEQ <$> decodeNoAnn- (0x03, 0x37) -> LT <$> decodeNoAnn- (0x03, 0x2A) -> GT <$> decodeNoAnn- (0x03, 0x32) -> LE <$> decodeNoAnn- (0x03, 0x28) -> GE <$> decodeNoAnn- (0x03, 0x30) -> INT <$> decodeNoAnn- (0x05, 0x55) -> CONTRACT <$> decodeNoAnn <*> decodeNoAnn <*> decodeType- (0x03, 0x4D) -> TRANSFER_TOKENS <$> decodeNoAnn- (0x03, 0x4E) -> SET_DELEGATE <$> decodeNoAnn- (0x05, 0x1D) -> do- contract <- decodeContract- CREATE_CONTRACT <$> decodeNoAnn <*> decodeNoAnn <*> pure contract- (0x03, 0x1E) -> IMPLICIT_ACCOUNT <$> decodeNoAnn- (0x03, 0x40) -> NOW <$> decodeNoAnn- (0x03, 0x13) -> AMOUNT <$> decodeNoAnn- (0x03, 0x15) -> BALANCE <$> decodeNoAnn- (0x03, 0x7b) -> VOTING_POWER <$> decodeNoAnn- (0x03, 0x7c) -> TOTAL_VOTING_POWER <$> decodeNoAnn- (0x03, 0x18) -> CHECK_SIGNATURE <$> decodeNoAnn- (0x03, 0x0F) -> SHA256 <$> decodeNoAnn- (0x03, 0x10) -> SHA512 <$> decodeNoAnn- (0x03, 0x0E) -> BLAKE2B <$> decodeNoAnn- (0x03, 0x7E) -> SHA3 <$> decodeNoAnn- (0x03, 0x7D) -> KECCAK <$> decodeNoAnn- (0x03, 0x2B) -> HASH_KEY <$> decodeNoAnn- (0x03, 0x7F) -> PAIRING_CHECK <$> decodeNoAnn- (0x03, 0x47) -> SOURCE <$> decodeNoAnn- (0x03, 0x48) -> SENDER <$> decodeNoAnn- (0x03, 0x49) -> SELF <$> decodeNoAnn <*> decodeNoAnn- (0x03, 0x54) -> ADDRESS <$> decodeNoAnn- (0x03, 0x75) -> CHAIN_ID <$> decodeNoAnn- (0x03, 0x76) -> LEVEL <$> decodeNoAnn- (0x03, 0x77) -> SELF_ADDRESS <$> decodeNoAnn- (0x03, 0x79) -> pure $ NEVER- -- Instructions with annotations from here on- (0x04, 0x21) -> DUP <$> decodeVAnn- (0x06, 0x21) -> flip DUPN <$> (expectTag "'DUP n' parameter" 0x00 *> decodeInt) <*> decodeVAnn- (0x08, 0x43) -> do- (typ, val) <- decodePushVal- an <- decodeVAnn- return $ PUSH an typ val- (0x04, 0x46) -> decodeWithTVAnns SOME- (0x06, 0x3E) -> do- t <- decodeType- decodeWithTVAnns NONE <*> pure t- (0x04, 0x4F) -> decodeWithTVAnns UNIT- (0x04, 0x42) -> decodeWithTVF2Anns PAIR- (0x06, 0x42) -> do- n <- decodeTaggedInt "'PAIR n' parameter"- varAnn <- decodeVAnn- pure $ PAIRN varAnn n- (0x04, 0x16) -> decodeWithVFAnns CAR- (0x04, 0x17) -> decodeWithVFAnns CDR- (0x06, 0x33) -> do- t <- decodeType- decodeWithTVF2Anns LEFT <*> pure t- (0x06, 0x44) -> do- t <- decodeType- decodeWithTVF2Anns RIGHT <*> pure t- (0x06, 0x3D) -> do- t <- decodeType- decodeWithTVAnns NIL <*> pure t- (0x04, 0x1B) -> CONS <$> decodeVAnn- (0x04, 0x45) -> SIZE<$> decodeVAnn- (0x06, 0x24) -> do- c <- decodeComparable- decodeWithTVAnns EMPTY_SET <*> pure c- (0x08, 0x23) -> do- c <- decodeComparable- t <- decodeType- decodeWithTVAnns EMPTY_MAP <*> pure c <*> pure t- (0x08, 0x72) -> do- c <- decodeComparable- t <- decodeType- decodeWithTVAnns EMPTY_BIG_MAP <*> pure c <*> pure t- (0x06, 0x38) -> do- o <- decodeOps- MAP <$> decodeVAnn <*> pure o- (0x04, 0x39) -> MEM <$> decodeVAnn- (0x04, 0x29) -> GET <$> decodeVAnn- (0x06, 0x29) -> do- n <- decodeTaggedInt "'GET n' parameter"- varAnn <- decodeVAnn- pure $ GETN varAnn n- (0x04, 0x50) -> UPDATE <$> decodeVAnn- (0x06, 0x50) -> do- n <- decodeTaggedInt "'UPDATE n' parameter"- varAnn <- decodeVAnn- pure $ UPDATEN varAnn n- (0x04, 0x8c) -> GET_AND_UPDATE <$> decodeVAnn- (0x04, 0x26) -> EXEC <$> decodeVAnn- (0x04, 0x73) -> APPLY <$> decodeVAnn- (0x06, 0x57) -> do- t <- decodeType- CAST <$> decodeVAnn <*> pure t- (0x04, 0x58) -> RENAME <$> decodeVAnn- (0x04, 0x0C) -> PACK <$> decodeVAnn- (0x06, 0x0D) -> do- t <- decodeType- decodeWithTVAnns UNPACK <*> pure t- (0x04, 0x1A) -> CONCAT <$> decodeVAnn- (0x04, 0x6F) -> SLICE <$> decodeVAnn- (0x04, 0x56) -> ISNAT <$> decodeVAnn- (0x04, 0x12) -> ADD <$> decodeVAnn- (0x04, 0x4B) -> SUB <$> decodeVAnn- (0x04, 0x3A) -> MUL <$> decodeVAnn- (0x04, 0x22) -> EDIV <$> decodeVAnn- (0x04, 0x11) -> ABS <$> decodeVAnn- (0x04, 0x3B) -> NEG <$> decodeVAnn- (0x04, 0x35) -> LSL <$> decodeVAnn- (0x04, 0x36) -> LSR <$> decodeVAnn- (0x04, 0x41) -> OR <$> decodeVAnn- (0x04, 0x14) -> AND <$> decodeVAnn- (0x04, 0x51) -> XOR <$> decodeVAnn- (0x04, 0x3F) -> NOT <$> decodeVAnn- (0x04, 0x19) -> COMPARE <$> decodeVAnn- (0x04, 0x25) -> EQ <$> decodeVAnn- (0x04, 0x3C) -> NEQ <$> decodeVAnn- (0x04, 0x37) -> LT <$> decodeVAnn- (0x04, 0x2A) -> GT <$> decodeVAnn- (0x04, 0x32) -> LE <$> decodeVAnn- (0x04, 0x28) -> GE <$> decodeVAnn- (0x04, 0x30) -> INT <$> decodeVAnn- (0x06, 0x55) -> do- t <- decodeType- decodeWithVFAnns CONTRACT <*> pure t- (0x04, 0x4D) -> TRANSFER_TOKENS <$> decodeVAnn- (0x04, 0x4E) -> SET_DELEGATE <$> decodeVAnn- (0x06, 0x1D) -> do- contract <- decodeContract- decodeWithV2Anns CREATE_CONTRACT <*> pure contract- (0x04, 0x1E) -> IMPLICIT_ACCOUNT <$> decodeVAnn- (0x04, 0x40) -> NOW <$> decodeVAnn- (0x04, 0x13) -> AMOUNT <$> decodeVAnn- (0x04, 0x15) -> BALANCE <$> decodeVAnn- (0x04, 0x7b) -> VOTING_POWER <$> decodeVAnn- (0x04, 0x7c) -> TOTAL_VOTING_POWER <$> decodeVAnn- (0x04, 0x18) -> CHECK_SIGNATURE <$> decodeVAnn- (0x04, 0x0F) -> SHA256 <$> decodeVAnn- (0x04, 0x10) -> SHA512 <$> decodeVAnn- (0x04, 0x0E) -> BLAKE2B <$> decodeVAnn- (0x04, 0x7E) -> SHA3 <$> decodeVAnn- (0x04, 0x7D) -> KECCAK <$> decodeVAnn- (0x04, 0x2B) -> HASH_KEY <$> decodeVAnn- (0x04, 0x7F) -> PAIRING_CHECK <$> decodeVAnn- (0x04, 0x47) -> SOURCE <$> decodeVAnn- (0x04, 0x48) -> SENDER <$> decodeVAnn- (0x04, 0x49) -> decodeWithVFAnns SELF- (0x04, 0x54) -> ADDRESS <$> decodeVAnn- (0x04, 0x75) -> CHAIN_ID <$> decodeVAnn- (0x04, 0x76) -> LEVEL <$> decodeVAnn- (0x04, 0x77) -> SELF_ADDRESS <$> decodeVAnn- (other1, other2) -> fail $ "Unknown instruction tag: " +|- bytesF [other1, other2]--decodePushVal :: Get (Ty, Value)-decodePushVal = do- typ <- decodeType- T.withSomeSingT (T.fromUType typ) $ \(_ :: Sing t) ->- case T.checkScope @(T.ConstantScope t) of- Left bt -> fail $ "Type can not appear in PUSH because it " <> pretty bt- Right Dict -> do- tval <- decodeValue @t- pure $ (typ, T.untypeValue tval)--decodeContract :: Get Contract-decodeContract = decodeAsList $ do- result <- contractTuple- case orderContractBlock result of- Just contract' -> do- pure contract'- Nothing ->- fail "Duplicate contract field."- where- decodeParamsBlock = CBParam <$> do- expectTag "Pre contract parameter" 0x05- expectTag "Contract parameter" 0x00- (t, ta, root) <- decodeTWithAnns- pure $ ParameterType (Ty t ta) root- decodeStorageBlock = CBStorage <$> do- expectTag "Pre contract storage" 0x05- expectTag "Contract storage" 0x01- decodeType- decodeCodeBlock = CBCode <$> do- expectTag "Pre contract code" 0x05- expectTag "Contract code" 0x02- decodeOps-- contractBlock = decodeParamsBlock <|> decodeStorageBlock <|> decodeCodeBlock-- contractTuple = do- result1 <- contractBlock- result2 <- contractBlock- result3 <- contractBlock- pure (result1, result2, result3)---decodeOp :: Get ExpandedOp-decodeOp = Get.label "Op" $ do- tag <- Get.lookAhead Get.getWord8- if tag == 0x02- then SeqEx <$> decodeOps ? "Ops seq"- else PrimEx <$> decodeInstr ? "One op"--decodeOps :: Get [ExpandedOp]-decodeOps = decodeAsList $ manyForced decodeOp--decodeComparable :: Get Ty-decodeComparable = do- (ct, tAnn, fAnn) <- decodeComparableTWithAnns- if fAnn == noAnn- then pure $ Ty ct tAnn- else fail "This Comparable should not have a Field annotation"--decodeType :: Get Ty-decodeType = do- (t, tAnn, fAnn) <- decodeTWithAnns- if fAnn == noAnn- then pure $ Ty t tAnn- else fail "This Type should not have a Field annotation"--decodeComparableTWithAnns :: Get (T, TypeAnn, FieldAnn)-decodeComparableTWithAnns = Get.label "Comparable primitive type" $ do- pretag <- Get.getWord8 ? "Pre simple comparable type tag"- tag <- Get.getWord8 ? "Simple comparable type tag"- let failMessage = "Unknown primitive tag: " +| bytesF [pretag, tag]- ct <- case tag of- 0x6C -> pure TUnit- 0x5B -> pure TInt- 0x62 -> pure TNat- 0x68 -> pure TString- 0x69 -> pure TBytes- 0x6A -> pure TMutez- 0x59 -> pure TBool- 0x5C -> pure TKey- 0x5D -> pure TKeyHash- 0x67 -> pure TSignature- 0x6B -> pure TTimestamp- 0x6E -> pure TAddress- 0x74 -> pure TChainId- 0x63 -> TOption <$> decodeType- 0x65 ->- case pretag of- 0x07 -> decodeTPair- 0x08 -> decodeTPair- 0x09 -> decodeTPairN- _ -> fail failMessage- 0x64 -> decodeTOr- _ -> fail failMessage- case pretag of- 0x03 -> (ct,,) <$> decodeNoAnn <*> decodeNoAnn- 0x04 -> decodeWithTFAnns (ct,,)- 0x05 ->- case tag of- 0x63 -> (ct,,) <$> decodeNoAnn <*> decodeNoAnn- _ -> decodeWithTFAnns (ct,,)- 0x06 -> decodeWithTFAnns (ct,,)- 0x07 -> (ct,,) <$> decodeNoAnn <*> decodeNoAnn- 0x08 -> decodeWithTFAnns (ct,,)- 0x09 -> decodeWithTFAnns (ct,,)- _ -> fail failMessage--{-# ANN decodeTWithAnns ("HLint: ignore Redundant <$>" :: Text) #-}-decodeTWithAnns :: Get (T, TypeAnn, FieldAnn)-decodeTWithAnns = doDecode <|> decodeComparableTWithAnns ? "Type"- where- doDecode = do- pretag <- Get.getWord8 ? "Pre complex type tag"- tag <- Get.getWord8 ? "Complex type tag"- case (pretag, tag) of- (0x03, 0x5C) ->- (,,) <$> pure TKey <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x6C) ->- (,,) <$> pure TUnit <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x78) ->- (,,) <$> pure TNever <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x67) ->- (,,) <$> pure TSignature <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x74) ->- (,,) <$> pure TChainId <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x82) ->- (,,) <$> pure TBls12381Fr <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x80) ->- (,,) <$> pure TBls12381G1 <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x81) ->- (,,) <$> pure TBls12381G2 <*> decodeNoAnn <*> decodeNoAnn- (0x05, 0x63) ->- (,,) <$> (TOption <$> decodeType) <*> decodeNoAnn <*> decodeNoAnn- (0x05, 0x5F) ->- (,,) <$> (TList <$> decodeType) <*> decodeNoAnn <*> decodeNoAnn- (0x05, 0x66) ->- (,,) <$> (TSet <$> decodeComparable) <*> decodeNoAnn <*> decodeNoAnn- (0x03, 0x6D) ->- (,,) <$> pure TOperation <*> decodeNoAnn <*> decodeNoAnn- (0x05, 0x5A) ->- (,,) <$> (TContract <$> decodeType) <*> decodeNoAnn <*> decodeNoAnn- (0x07, 0x5E) ->- (,,) <$> (TLambda <$> decodeType <*> decodeType) <*> decodeNoAnn <*> decodeNoAnn- (0x07, 0x60) ->- (,,) <$> (TMap <$> decodeComparable <*> decodeType) <*> decodeNoAnn <*> decodeNoAnn- (0x07, 0x61) ->- (,,) <$> (TBigMap <$> decodeComparable <*> decodeType) <*> decodeNoAnn <*> decodeNoAnn- -- T with annotations from here on- (0x04, 0x5C) -> decodeWithTFAnns (TKey,,)- (0x04, 0x6C) -> decodeWithTFAnns (TUnit,,)- (0x04, 0x78) -> decodeWithTFAnns (TNever,,)- (0x04, 0x67) -> decodeWithTFAnns (TSignature,,)- (0x04, 0x74) -> decodeWithTFAnns (TChainId,,)- (0x06, 0x63) -> do- t <- TOption <$> decodeType- decodeWithTFAnns (t,,)- (0x06, 0x5F) -> do- t <- TList <$> decodeType- decodeWithTFAnns (t,,)- (0x06, 0x66) -> do- t <- TSet <$> decodeComparable- decodeWithTFAnns (t,,)- (0x04, 0x6D) -> decodeWithTFAnns (TOperation,,)- (0x06, 0x5A) -> do- t <- TContract <$> decodeType- decodeWithTFAnns (t,,)- (0x08, 0x5E) -> do- t <- TLambda <$> decodeType <*> decodeType- decodeWithTFAnns (t,,)- (0x08, 0x60) -> do- t <- TMap <$> decodeComparable <*> decodeType- decodeWithTFAnns (t,,)- (0x08, 0x61) -> do- t <- TBigMap <$> decodeComparable <*> decodeType- decodeWithTFAnns (t,,)- (other1, other2) -> fail $ "Unknown primitive tag: " +|- bytesF [other1, other2]---- | "Normal" pair notation, e.g. `pair int int` or `pair int (pair int int)`------ The pair type doesn't really carry its nested variable annotations, except--- during execution. For this reason, they don't get decoded here and these--- variable annotations fields will be empty. See !763 for more context.-decodeTPair :: Get T-decodeTPair = do- (t1, tAnn1, fAnn1) <- decodeTWithAnns- (t2, tAnn2, fAnn2) <- decodeTWithAnns- pure $ TPair fAnn1 fAnn2 noAnn noAnn (Ty t1 tAnn1) (Ty t2 tAnn2)---- | Right-combed notation, e.g. `pair int int int`------ Just like 'decodeTPair', nested variable annotations are not decoded, as they--- exist only during execution. See !763 for more context.-decodeTPairN :: Get T-decodeTPairN = do- -- Find out how many bytes it took to encode the pair's fields, and decode them.- fieldsLen <- decodeLength ? "'pair' number of type arguments"- fields <- Get.isolate fieldsLen (manyForced decodeTWithAnns) ? "'pair' type arguments"- go fields- where- go :: [(T, TypeAnn, FieldAnn)] -> Get T- go = \case- [] -> fail "The 'pair' type expects at least 2 type arguments, but 0 were given."- [(t, _, _)] -> fail $ "The 'pair' type expects at least 2 type arguments, but only 1 was given: '" <> pretty t <> "'."- [(t1, tAnn1, fAnn1), (t2, tAnn2, fAnn2)] ->- pure $ TPair fAnn1 fAnn2 noAnn noAnn (Ty t1 tAnn1) (Ty t2 tAnn2)- (t1, t1Ann1, fAnn1) : fields -> do- rightCombedT <- go fields- pure $ TPair fAnn1 noAnn noAnn noAnn (Ty t1 t1Ann1) (Ty rightCombedT noAnn)--decodeTOr :: Get T-decodeTOr = do- (t1, tAnn1, fAnn1) <- decodeTWithAnns- (t2, tAnn2, fAnn2) <- decodeTWithAnns- pure $ TOr fAnn1 fAnn2 (Ty t1 tAnn1) (Ty t2 tAnn2)--------------------------------------------------------------------------------- Annotations--------------------------------------------------------------------------------- | Utility function to fill a constructor with an empty annotation-decodeNoAnn :: forall (t :: Type). Get (Annotation t)-decodeNoAnn = pure noAnn---- | Decodes an annotations' string and uses the provided `Parser` to parse--- untyped annotations from it. This has to produce at least one annotation--- (Annotations' String parsing will fail otherwise)-decodeAnns :: Parser a -> Get a-decodeAnns annsParser = do- l <- decodeLength ? "Annotations' String length"- ss <- replicateM l Get.getWord8 ? "Annotations' String content"- s <- decodeUtf8' (BS.pack ss)- & either (fail . show) pure- ? "Annotations' String UTF-8 decoding"- either (fail . displayException . ParserException) pure $ parseNoEnv annsParser "" s--decodeVAnn :: Get VarAnn-decodeVAnn = decodeAnns PA.noteV--decodeVAnnDef :: Get VarAnn-decodeVAnnDef = decodeAnns PA.noteDef--decodeWithTVAnns :: (TypeAnn -> VarAnn -> a) -> Get a-decodeWithTVAnns f = do- (tAnn, vAnn) <- decodeAnns PA.notesTV- pure $ f tAnn vAnn--decodeWithTVF2Anns :: (TypeAnn -> VarAnn -> FieldAnn -> FieldAnn -> a) -> Get a-decodeWithTVF2Anns f = do- (tAnn, vAnn, (fAnn1, fAnn2)) <- decodeAnns PA.notesTVF2Def- pure $ f tAnn vAnn fAnn1 fAnn2--decodeWithTFAnns :: (TypeAnn -> FieldAnn -> a) -> Get a-decodeWithTFAnns f = do- (tAnn, fAnn) <- decodeAnns PA.notesTF- pure $ f tAnn fAnn+unpackInstr' = unpackImpl @([ExpandedOp]) -decodeWithV2Anns :: (VarAnn -> VarAnn -> a) -> Get a-decodeWithV2Anns f = do- (vAnn1, vAnn2) <- decodeAnns PA.noteV2Def- pure $ f vAnn1 vAnn2+-- | Deserialize bytes into 'Untyped.Value'.+unpackUValue' :: ByteString -> Either UnpackError U.Value+unpackUValue' = unpackImpl @U.Value -decodeWithVFAnns :: (VarAnn -> FieldAnn -> a) -> Get a-decodeWithVFAnns f = do- (vAnn, fAnn) <- decodeAnns PA.notesVF- pure $ f vAnn fAnn+unpackImpl :: forall t. (FromExpression t)+ => ByteString+ -> Either UnpackError t+unpackImpl bs = do+ (tag, bs') <- maybeToRight (UnpackError "Empty bytes") (BS.uncons bs)+ when (tag /= 0x05) . Left . UnpackError $+ "Unexpected tag: '" <> (show tag) <> "'. '0x05' tag expected."+ expr <- eitherDecodeExpression bs'+ either (Left . UnpackError . pretty) Right $ fromExpression @t expr
src/Michelson/Macro.hs view
@@ -25,7 +25,6 @@ -- * For parsing , mapPairLeaves- , mapUnpairLeaves -- * Internals exported for tests , expand@@ -74,7 +73,7 @@ build = genericF data UnpairStruct- = UF (VarAnn, FieldAnn)+ = UF | UP UnpairStruct UnpairStruct deriving stock (Eq, Show, Data, Generic) @@ -139,7 +138,7 @@ | IFCMP ParsedInstr VarAnn [ParsedOp] [ParsedOp] | FAIL | PAPAIR PairStruct TypeAnn VarAnn- | UNPAIR UnpairStruct+ | UNPAPAIR UnpairStruct | CADR [CadrStruct] VarAnn FieldAnn | CARN VarAnn Word | CDRN VarAnn Word@@ -172,7 +171,7 @@ IFCMP parsedInstr varAnn parsedOps1 parsedOps2 -> "<IFCMP: "+|parsedInstr|+", "+|varAnn|+", "+|parsedOps1|+", "+|parsedOps2|+">" FAIL -> "FAIL" PAPAIR pairStruct typeAnn varAnn -> "<PAPAIR: "+|pairStruct|+", "+|typeAnn|+", "+|varAnn|+">"- UNPAIR pairStruct -> "<UNPAIR: "+|pairStruct|+">"+ UNPAPAIR pairStruct -> "<UNPAPAIR: "+|pairStruct|+">" CADR cadrStructs varAnn fieldAnn -> "<CADR: "+|cadrStructs|+", "+|varAnn|+", "+|fieldAnn|+">" CARN varAnn idx -> "<CAR: #"+||idx||+","+||varAnn||+">" CDRN varAnn idx -> "<CDR: #"+||idx||+","+||varAnn||+">"@@ -248,9 +247,9 @@ expandMacro :: InstrCallStack -> Macro -> [ExpandedOp] expandMacro p@InstrCallStack{icsCallStack=cs,icsSrcPos=macroPos} = \case- VIEW a -> expandMacro p (UNPAIR $ UP (UF (noAnn, noAnn)) (UF (noAnn, noAnn))) ++- [ PrimEx (DIP $ oprimEx $ DUPN noAnn 2) ] ++- [ PrimEx $ PAIR noAnn noAnn noAnn noAnn ] +++ VIEW a -> [ PrimEx (UNPAIR noAnn noAnn noAnn noAnn)+ , PrimEx (DIP $ oprimEx $ DUPN noAnn 2)+ , PrimEx $ PAIR noAnn noAnn noAnn noAnn ] ++ (expand cs <$> a) ++ [ PrimEx (DIP [PrimEx $ AMOUNT noAnn]) , PrimEx $ TRANSFER_TOKENS noAnn@@ -259,8 +258,8 @@ , PrimEx $ CONS noAnn , PrimEx $ PAIR noAnn noAnn noAnn noAnn ]- VOID a -> expandMacro p (UNPAIR (UP (UF (noAnn, noAnn)) (UF (noAnn, noAnn)))) ++- [ PrimEx SWAP+ VOID a -> [ PrimEx (UNPAIR noAnn noAnn noAnn noAnn)+ , PrimEx SWAP , PrimEx $ DIP $ expand cs <$> a , PrimEx SWAP , PrimEx $ EXEC noAnn@@ -285,7 +284,7 @@ ASSERT_LEFT -> oprimEx $ IF_LEFT [] (expandMacro p FAIL) ASSERT_RIGHT -> oprimEx $ IF_LEFT (expandMacro p FAIL) [] PAPAIR ps t v -> expandPapair p ps t v- UNPAIR ps -> expandUnpapair p ps+ UNPAPAIR ps -> expandUnpapair p ps CADR c v f -> expandCadr p c v f CARN v idx -> [PrimEx (GETN v (2 * idx + 1))] CDRN v idx -> [PrimEx (GETN v (2 * idx))]@@ -301,50 +300,58 @@ xo = PrimEx . fmap (expand cs) xp = fmap (expand cs) --- the correctness of type-annotation expansion is currently untested, as these--- expansions are not explicitly documented in the Michelson Specification+-- | The macro expansion rules below were taken from: https://tezos.gitlab.io/008/michelson.html#syntactic-conveniences+--+-- The correctness of type-annotation expansion is currently untested, as these+-- expansions are not explicitly documented in the Michelson Specification. expandPapair :: InstrCallStack -> PairStruct -> TypeAnn -> VarAnn -> [ExpandedOp] expandPapair ics ps t v = case ps of P (F a) (F b) -> [PrimEx $ PAIR t v a b]++ -- > PA(\right)R / S => DIP ((\right)R) ; PAIR / S P (F a) r -> PrimEx <$> [ DIP $ expandMacro ics (PAPAIR r noAnn noAnn) , PAIR t v a noAnn]++ -- > P(\left)IR / S => (\left)R ; PAIR / S P l (F b) -> expandMacro ics (PAPAIR l noAnn noAnn) ++ [PrimEx $ PAIR t v noAnn b]++ -- > P(\left)(\right)R => (\left)R ; DIP ((\right)R) ; PAIR / S P l r -> expandMacro ics (PAPAIR l noAnn noAnn) ++ [ PrimEx $ DIP $ expandMacro ics (PAPAIR r noAnn noAnn) , PrimEx $ PAIR t v noAnn noAnn]- F _ -> [] -- Do nothing in this case.+ -- It's impossible from the structure of PairStruct and considered cases above, -- but if it accidentally happened let's just do nothing.+ F _ -> [] +-- | The macro expansion rules below were taken from: https://tezos.gitlab.io/008/michelson.html#syntactic-conveniences expandUnpapair :: InstrCallStack -> UnpairStruct -> [ExpandedOp] expandUnpapair ics = \case- UP (UF (v,f)) (UF (w,g)) ->- PrimEx <$> [ DUP noAnn- , CAR v f- , DIP [PrimEx $ CDR w g]- ]- UP (UF (v, f)) r ->- PrimEx <$> [ DUP noAnn- , CAR v f- , DIP (PrimEx (CDR noAnn noAnn) : expandMacro ics (UNPAIR r))+ UP UF UF ->+ [ PrimEx (UNPAIR noAnn noAnn noAnn noAnn) ]++ -- > UNPA(\right)R / S => UNPAIR ; DIP (UN(\right)R) / S+ UP UF r ->+ PrimEx <$> [ UNPAIR noAnn noAnn noAnn noAnn+ , DIP (expandMacro ics (UNPAPAIR r)) ]- UP l (UF (v, f)) ->- map PrimEx [ DUP noAnn- , DIP [PrimEx $ CDR v f]- , CAR noAnn noAnn- ] ++- expandMacro ics (UNPAIR l)++ -- > UNP(\left)IR / S => UNPAIR ; UN(\left)R / S+ UP l UF ->+ PrimEx (UNPAIR noAnn noAnn noAnn noAnn)+ : expandMacro ics (UNPAPAIR l)++ -- > UNP(\left)(\right)R => UNPAIR ; DIP (UN(\right)R) ; UN(\left)R / S UP l r ->- expandMacro ics unpairOne ++- [PrimEx $ DIP $ expandMacro ics $ UNPAIR r] ++- expandMacro ics (UNPAIR l)- UF _ -> [] -- Do nothing in this case.+ [ PrimEx (UNPAIR noAnn noAnn noAnn noAnn)+ , PrimEx $ DIP $ expandMacro ics $ UNPAPAIR r+ ] +++ expandMacro ics (UNPAPAIR l)+ -- It's impossible from the structure of UnpairStruct and considered cases above, -- but if it accidentally happened let's just do nothing.- where- unpairOne = UNPAIR (UP fn fn)- fn = UF (noAnn, noAnn)+ UF -> [] expandCadr :: InstrCallStack -> [CadrStruct] -> VarAnn -> FieldAnn -> [ExpandedOp] expandCadr ics cs v f = case cs of@@ -455,22 +462,6 @@ where getLeaf (a:as) = (a, as) getLeaf _ = (noAnn, [])--mapUnpairLeaves :: [(VarAnn, FieldAnn)] -> UnpairStruct -> UnpairStruct-mapUnpairLeaves fs p = evalState (unpairLeavesST p) fs--unpairLeavesST :: UnpairStruct -> State [(VarAnn, FieldAnn)] UnpairStruct-unpairLeavesST = \case- (UP l r) -> do- l' <- unpairLeavesST l- r' <- unpairLeavesST r- return $ UP l' r'- (UF _) -> do- f <- state getLeaf- return $ UF f- where- getLeaf (a:as) = (a, as)- getLeaf _ = ((noAnn, noAnn), []) deriveJSON morleyAesonOptions ''ParsedOp deriveJSON morleyAesonOptions ''LetMacro
src/Michelson/Optimizer.hs view
@@ -46,7 +46,7 @@ import Michelson.Typed.T import Michelson.Typed.Util (DfsSettings(..), dfsInstr) import Michelson.Typed.Value-import Util.Peano (SingNat(..))+import Util.PeanoNatural ---------------------------------------------------------------------------- -- High level@@ -98,6 +98,8 @@ defaultRules = flattenSeqLHS `orSimpleRule` removeNesting+ `orSimpleRule` removeExtStackType+ `orSimpleRule` flattenFn `orSimpleRule` dipDrop2swapDrop `orSimpleRule` ifNopNop2Drop `orSimpleRule` nopIsNeutralForSeq@@ -134,9 +136,20 @@ Nested i -> Just i _ -> Nothing +-- | STACKTYPE is currently a Nop and may safely be removed.+removeExtStackType :: Rule+removeExtStackType = \case+ Ext (STACKTYPE{}) -> Just Nop+ _ -> Nothing++flattenFn :: Rule+flattenFn = \case+ Fn _ _ i -> Just i+ _ -> Nothing+ dipDrop2swapDrop :: Rule dipDrop2swapDrop = \case- DIP DROP -> Just $ Seq SWAP DROP+ DIP DROP -> Just $ SWAP :# DROP _ -> Nothing ifNopNop2Drop :: Rule@@ -146,99 +159,99 @@ nopIsNeutralForSeq :: Rule nopIsNeutralForSeq = \case- Seq Nop i -> Just i- Seq i Nop -> Just i+ Nop :# i -> Just i+ i :# Nop -> Just i _ -> Nothing variousNops :: Rule variousNops = \case- Seq SWAP (Seq SWAP c) -> Just c- Seq (PUSH _) (Seq DROP c) -> Just c- Seq DUP (Seq DROP c) -> Just c- Seq UNIT (Seq DROP c) -> Just c- Seq NOW (Seq DROP c) -> Just c- Seq SENDER (Seq DROP c) -> Just c- Seq EMPTY_MAP (Seq DROP c) -> Just c- Seq EMPTY_SET (Seq DROP c) -> Just c+ SWAP :# SWAP :# c -> Just c+ PUSH _ :# DROP :# c -> Just c+ DUP :# DROP :# c -> Just c+ UNIT :# DROP :# c -> Just c+ NOW :# DROP :# c -> Just c+ SENDER :# DROP :# c -> Just c+ EMPTY_MAP :# DROP :# c -> Just c+ EMPTY_SET :# DROP :# c -> Just c - Seq SWAP SWAP -> Just Nop- Seq (PUSH _) DROP -> Just Nop- Seq DUP DROP -> Just Nop- Seq UNIT DROP -> Just Nop- Seq NOW DROP -> Just Nop- Seq SENDER DROP -> Just Nop- Seq EMPTY_MAP DROP -> Just Nop- Seq EMPTY_SET DROP -> Just Nop- _ -> Nothing+ SWAP :# SWAP -> Just Nop+ PUSH _ :# DROP -> Just Nop+ DUP :# DROP -> Just Nop+ UNIT :# DROP -> Just Nop+ NOW :# DROP -> Just Nop+ SENDER :# DROP -> Just Nop+ EMPTY_MAP :# DROP -> Just Nop+ EMPTY_SET :# DROP -> Just Nop+ _ -> Nothing dupSwap2dup :: Rule dupSwap2dup = \case- Seq DUP (Seq SWAP c) -> Just (Seq DUP c)- Seq DUP SWAP -> Just DUP- _ -> Nothing+ DUP :# SWAP :# c -> Just (DUP :# c)+ DUP :# SWAP -> Just DUP+ _ -> Nothing noDipNeeded :: Rule noDipNeeded = \case -- If we put a constant value on stack and then do something under it, -- we can do this "something" on original stack and then put that constant.- Seq (PUSH x) (Seq (DIP f) c) -> Just (Seq f (Seq (PUSH x) c))- Seq (PUSH x) (DIP f) -> Just (Seq f (PUSH x))- Seq UNIT (Seq (DIP f) c) -> Just (Seq f (Seq UNIT c))- Seq UNIT (DIP f) -> Just (Seq f UNIT)- Seq NOW (Seq (DIP f) c) -> Just (Seq f (Seq NOW c))- Seq NOW (DIP f) -> Just (Seq f NOW)- Seq SENDER (Seq (DIP f) c) -> Just (Seq f (Seq SENDER c))- Seq SENDER (DIP f) -> Just (Seq f SENDER)- Seq EMPTY_MAP (Seq (DIP f) c) -> Just (Seq f (Seq EMPTY_MAP c))- Seq EMPTY_MAP (DIP f) -> Just (Seq f EMPTY_MAP)- Seq EMPTY_SET (Seq (DIP f) c) -> Just (Seq f (Seq EMPTY_SET c))- Seq EMPTY_SET (DIP f) -> Just (Seq f EMPTY_SET)+ PUSH x :# DIP f :# c -> Just $ f :# PUSH x :# c+ PUSH x :# DIP f -> Just $ f :# PUSH x+ UNIT :# DIP f :# c -> Just $ f :# UNIT :# c+ UNIT :# DIP f -> Just $ f :# UNIT+ NOW :# DIP f :# c -> Just $ f :# NOW :# c+ NOW :# DIP f -> Just $ f :# NOW+ SENDER :# DIP f :# c -> Just $ f :# SENDER :# c+ SENDER :# DIP f -> Just $ f :# SENDER+ EMPTY_MAP :# DIP f :# c -> Just $ f :# EMPTY_MAP :# c+ EMPTY_MAP :# DIP f -> Just $ f :# EMPTY_MAP+ EMPTY_SET :# DIP f :# c -> Just $ f :# EMPTY_SET :# c+ EMPTY_SET :# DIP f -> Just $ f :# EMPTY_SET -- If we do something ignoring top of the stack and then immediately -- drop top of the stack, we can drop that item in advance and -- not use 'DIP' at all.- Seq (DIP f) (Seq DROP c) -> Just (Seq DROP (Seq f c))- Seq (DIP f) DROP -> Just (Seq DROP f)+ DIP f :# DROP :# c -> Just $ DROP :# f :# c+ DIP f :# DROP -> Just $ DROP :# f - _ -> Nothing+ _ -> Nothing branchShortCut :: Rule branchShortCut = \case- Seq LEFT (Seq (IF_LEFT f _) c) -> Just (Seq f c)- Seq RIGHT (Seq (IF_LEFT _ f) c) -> Just (Seq f c)- Seq CONS (Seq (IF_CONS f _) c) -> Just (Seq f c)- Seq NIL (Seq (IF_CONS _ f) c) -> Just (Seq f c)- Seq NONE (Seq (IF_NONE f _) c) -> Just (Seq f c)- Seq SOME (Seq (IF_NONE _ f) c) -> Just (Seq f c)+ LEFT :# IF_LEFT f _ :# c -> Just (f :# c)+ RIGHT :# IF_LEFT _ f :# c -> Just (f :# c)+ CONS :# IF_CONS f _ :# c -> Just (f :# c)+ NIL :# IF_CONS _ f :# c -> Just (f :# c)+ NONE :# IF_NONE f _ :# c -> Just (f :# c)+ SOME :# IF_NONE _ f :# c -> Just (f :# c) - Seq (PUSH (VBool True)) (Seq (IF f _) c) -> Just (Seq f c)- Seq (PUSH (VBool False)) (Seq (IF _ f) c) -> Just (Seq f c)+ PUSH (VBool True) :# IF f _ :# c -> Just (f :# c)+ PUSH (VBool False) :# IF _ f :# c -> Just (f :# c) - Seq LEFT (IF_LEFT f _) -> Just f- Seq RIGHT (IF_LEFT _ f) -> Just f- Seq CONS (IF_CONS f _) -> Just f- Seq NIL (IF_CONS _ f) -> Just f- Seq NONE (IF_NONE f _) -> Just f- Seq SOME (IF_NONE _ f) -> Just f+ LEFT :# IF_LEFT f _ -> Just f+ RIGHT :# IF_LEFT _ f -> Just f+ CONS :# IF_CONS f _ -> Just f+ NIL :# IF_CONS _ f -> Just f+ NONE :# IF_NONE f _ -> Just f+ SOME :# IF_NONE _ f -> Just f - Seq (PUSH (VBool True)) (IF f _) -> Just f- Seq (PUSH (VBool False)) (IF _ f) -> Just f+ PUSH (VBool True) :# IF f _ -> Just f+ PUSH (VBool False) :# IF _ f -> Just f _ -> Nothing compareWithZero :: Rule compareWithZero = \case- Seq (PUSH (VInt 0)) (Seq COMPARE (Seq EQ c)) -> Just (Seq EQ c)- Seq (PUSH (VNat 0)) (Seq COMPARE (Seq EQ c)) -> Just (Seq INT (Seq EQ c))- Seq (PUSH (VInt 0)) (Seq COMPARE EQ) -> Just EQ- Seq (PUSH (VNat 0)) (Seq COMPARE EQ) -> Just (Seq INT EQ)- _ -> Nothing+ PUSH (VInt 0) :# COMPARE :# EQ :# c -> Just $ EQ :# c+ PUSH (VNat 0) :# COMPARE :# EQ :# c -> Just $ INT :# EQ :# c+ PUSH (VInt 0) :# COMPARE :# EQ -> Just $ EQ+ PUSH (VNat 0) :# COMPARE :# EQ -> Just $ INT :# EQ+ _ -> Nothing simpleDrops :: Rule simpleDrops = \case -- DROP 0 is Nop- Seq (DROPN SZ) c -> Just c- DROPN SZ -> Just Nop+ DROPN Zero :# c -> Just c+ DROPN Zero -> Just Nop -- DROP 1 is DROP. -- @gromak: DROP seems to be cheaper (in my experiments it consumed 3 less gas).@@ -251,8 +264,8 @@ -- I will leave this note and rule here in hope that someone will manage to -- deal with this problem one day. - -- Seq (DROPN (SS SZ)) c -> Just (Seq DROP c)- -- DROPN (SS SZ) -> Just DROP+ -- DROPN One :# c -> Just (DROP :# c)+ -- DROPN One -> Just DROP _ -> Nothing @@ -263,27 +276,27 @@ -- 'MAP' as well (which is harder). internalNop :: Rule internalNop = \case- DIP Nop -> Just Nop- Seq (DIP Nop) c -> Just c+ DIP Nop -> Just Nop+ DIP Nop :# c -> Just c _ -> Nothing simpleDips :: Rule simpleDips = \case -- DIP 0 is redundant- Seq (DIPN SZ i) c -> Just (Seq i c)- DIPN SZ i -> Just i+ DIPN Zero i :# c -> Just (i :# c)+ DIPN Zero i -> Just i -- @gromak: same situation as with `DROP 1` (see above).- -- Seq (DIPN (SS SZ) i) c -> Just (Seq (DIP i) c)- -- DIPN (SS SZ) i -> Just (DIP i)+ -- DIPN One i :# c -> Just (DIP i :# c)+ -- DIPN One i -> Just (DIP i) _ -> Nothing adjacentDips :: Rule adjacentDips = \case- Seq (DIP f) (DIP g) -> Just (DIP (Seq f g))- Seq (DIP f) (Seq (DIP g) c) -> Just (DIP (Seq f g) `Seq` c)+ DIP f :# DIP g -> Just (DIP (f :# g))+ DIP f :# DIP g :# c -> Just (DIP (f :# g) :# c) _ -> Nothing @@ -293,18 +306,18 @@ -- When @n@ is 2 it saves gas only. adjacentDrops :: Rule adjacentDrops = \case- Seq DROP DROP -> Just (DROPN (SS $ SS SZ))- Seq DROP (Seq DROP c) -> Just (DROPN (SS $ SS SZ) `Seq` c)+ DROP :# DROP -> Just (DROPN Two)+ DROP :# DROP :# c -> Just (DROPN Two :# c) -- Does not compile, need to do something smart- -- Seq (DROPN (SS (SS SZ))) DROP -> Just (DROPN (SS $ SS $ SS SZ))+ -- DROPN Two :# DROP -> Just (DROPN (Succ Two)) _ -> Nothing specificPush :: Rule specificPush = \case- push@PUSH{} -> optimizePush push- Seq (push@PUSH{}) c -> (`Seq` c) <$> optimizePush push+ push@PUSH{} -> optimizePush push+ push@PUSH{} :# c -> (:# c) <$> optimizePush push _ -> Nothing where@@ -323,33 +336,29 @@ isSomeOnIf :: Rule isSomeOnIf = \case- Seq (IF (PUSH (VOption Just{})) (PUSH (VOption Nothing))) c -> case c of- Seq (IF_NONE (PUSH (VBool False)) (Seq DROP (PUSH (VBool True)))) s -> Just s- IF_NONE (PUSH (VBool False)) (Seq DROP (PUSH (VBool True))) -> Just Nop+ IF (PUSH (VOption Just{})) (PUSH (VOption Nothing)) :# c -> case c of+ IF_NONE (PUSH (VBool False)) (DROP :# PUSH (VBool True)) :# s -> Just s+ IF_NONE (PUSH (VBool False)) (DROP :# PUSH (VBool True)) -> Just Nop _ -> Nothing _ -> Nothing --- UNPAIR with continuation-pattern UNPAIR_c- :: ()- => (i ~ ('TPair a b : s), i' ~ (a : b : s), o' ~ o)- => Instr i' o' -> Instr i o-pattern UNPAIR_c c = Seq DUP (Seq CAR (Seq (DIP CDR) c))- pairUnpair :: Rule pairUnpair = \case- Seq PAIR (UNPAIR_c c) -> Just c- Seq PAIR UNPAIR -> Just Nop+ PAIR :# UNPAIR :# c -> Just c+ PAIR :# UNPAIR -> Just Nop - UNPAIR_c (Seq PAIR c) -> Just c- UNPAIR_c PAIR -> Just Nop+ UNPAIR :# PAIR :# c -> Just c+ UNPAIR :# PAIR -> Just Nop _ -> Nothing unpairMisc :: Rule unpairMisc = \case- Seq UNPAIR SWAP -> Just (DUP `Seq` CDR `Seq` DIP CAR)- Seq UNPAIR (Seq SWAP c) -> Just (DUP `Seq` CDR `Seq` DIP CAR `Seq` c)+ DUP :# CAR :# DIP CDR -> Just $ UNPAIR+ DUP :# CAR :# DIP CDR :# c -> Just $ UNPAIR :# c++ DUP :# CDR :# DIP CAR -> Just $ UNPAIR :# SWAP+ DUP :# CDR :# DIP CAR :# c -> Just $ UNPAIR :# SWAP :# c _ -> Nothing commuteArith ::@@ -364,15 +373,15 @@ swapBeforeCommutative :: Rule swapBeforeCommutative = \case- Seq SWAP (Seq i c) -> (`Seq` c) <$> commuteArith i- Seq SWAP i -> commuteArith i+ SWAP :# i :# c -> (:# c) <$> commuteArith i+ SWAP :# i -> commuteArith i _ -> Nothing pushPack :: Rule pushPack = \case- Seq (PUSH x) PACK -> Just (pushPacked x)- Seq (PUSH x) (Seq PACK c) -> Just (pushPacked x `Seq` c)+ PUSH x :# PACK -> Just (pushPacked x)+ PUSH x :# PACK :# c -> Just (pushPacked x :# c) _ -> Nothing where
src/Michelson/Parser.hs view
@@ -20,6 +20,8 @@ , parseNoEnv , parseValue , parseExpandValue+ , parseValueFromFile+ , parseExpandValueFromFile -- * For tests , codeEntry@@ -46,8 +48,8 @@ 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)+ (Parsec, choice, customFailure, eitherP, eof, errorBundlePretty, getSourcePos, hidden, lookAhead,+ parse, try) import Text.Megaparsec.Pos (SourcePos(..), unPos) import Michelson.ErrorPos (SrcPos(..), unsafeMkPos)@@ -175,6 +177,15 @@ -- | Parse untyped value from text which comes from something that is -- not a file (which is often the case). So we assume it does not need -- any parsing environment.+--+-- >>> parseValue "{PUSH int aaa}"+-- Left 1:11:+-- |+-- 1 | {PUSH int aaa}+-- | ^^^^+-- unexpected "aaa}"+-- expecting value+-- <BLANKLINE> parseValue :: Text -> Either ParserException ParsedValue parseValue = first ParserException . parseNoEnv value "" @@ -182,6 +193,15 @@ parseExpandValue :: Text -> Either ParserException U.Value parseExpandValue = fmap expandValue . parseValue +-- | Like 'parseValue', but from text that comes from a file,+-- for which we get the 'FilePath'.+parseValueFromFile :: FilePath -> Text -> Either ParserException ParsedValue+parseValueFromFile filePath = first ParserException . parseNoEnv value filePath -- TODO remove filPath?++-- | Like 'parseValueFromFile', but also expands macros.+parseExpandValueFromFile :: FilePath -> Text -> Either ParserException U.Value+parseExpandValueFromFile filePath = fmap expandValue . parseValueFromFile filePath+ -- Primitive instruction ------------------ @@ -200,6 +220,15 @@ bracewrappedOps :: Parser [ParsedOp] bracewrappedOps = lookAhead (symbol "{") *> ops +-- |+-- >>> first ParserException $ parseNoEnv parsedOp "" "{a}"+-- Left 1:2:+-- |+-- 1 | {a}+-- | ^+-- unexpected 'a'+-- expecting '{', '}', macro, morley instruction, or primitive instruction+-- <BLANKLINE> parsedOp :: Parser ParsedOp parsedOp = do lms <- asks letMacros@@ -256,7 +285,8 @@ -- Some of the operations and macros have the same prefixes in their names -- So this case should be handled separately primOrMac :: Parser ParsedOp-primOrMac = (macWithPos (ifCmpMac parsedOp) <|> ifOrIfX)+primOrMac = hidden+ $ (macWithPos (ifCmpMac parsedOp) <|> ifOrIfX) <|> (macWithPos (mapCadrMac parsedOp) <|> primWithPos (mapOp parsedOp)) <|> (try (primWithPos pairOp) <|> try (primWithPos pairNOp) <|> macWithPos pairMac) <|> (try (macWithPos duupMac) <|> primWithPos dupOp)@@ -282,6 +312,16 @@ -- -- >>> [utypeQ| (int :a | nat :b) |] -- Ty (TOr % % (Ty TInt :a) (Ty TNat :b)) :+--+-- >>> [utypeQ|a|]+-- <BLANKLINE>+-- ...+-- |+-- 1 | a+-- | ^+-- unexpected 'a'+-- expecting type+-- ... utypeQ :: TH.QuasiQuoter utypeQ = parserToQuasiQuoter type_
src/Michelson/Parser/Annotations.hs view
@@ -9,8 +9,8 @@ , noteDef , noteV2Def , notesTVF- , notesTVF2 , notesTVF2Def+ , notesVVFF , notesTV , notesTF , notesVF@@ -37,14 +37,14 @@ note = lexeme $ string (annPrefix @tag) >> (specialNote <|> note' <|> emptyNote) where -- TODO [#48] these are special annotations and should not always be accepted- specialVNote = mkAnnotationUnsafe <$> asum (map string specialVarAnns)- specialFNote = mkAnnotationUnsafe <$> string specialFieldAnn+ specialVNote = unsafeMkAnnotation <$> asum (map string specialVarAnns)+ specialFNote = unsafeMkAnnotation <$> string specialFieldAnn specialNote = specialVNote <|> specialFNote emptyNote = pure noAnn note' = do a <- satisfy isValidAnnStart b <- takeWhileP Nothing isValidAnnBodyChar- return . mkAnnotationUnsafe $ T.cons a b+ return . unsafeMkAnnotation $ T.cons a b noteV :: Parser VarAnn noteV = note@@ -55,20 +55,29 @@ noteF :: Parser FieldAnn noteF = note -noteF2 :: Parser (FieldAnn, FieldAnn)-noteF2 = do a <- note; b <- note; return (a, b)- noteV2Def :: Parser (VarAnn, VarAnn) noteV2Def = permute2Def note note notesTVF :: Parser (TypeAnn, VarAnn, FieldAnn) notesTVF = permute3Def note note note -notesTVF2 :: Parser (TypeAnn, VarAnn, (FieldAnn, FieldAnn))-notesTVF2 = permute3Def note note noteF2- notesTVF2Def :: Parser (TypeAnn, VarAnn, (FieldAnn, FieldAnn)) notesTVF2Def = permute3Def note note (permute2Def note note)++-- | Parse 0/1/2 var anns and 0/1/2 field anns.+-- It doesn't matter which come first, so long as annotations of the same type appear together.+--+-- E.g.:+--+-- * "" is valid+-- * "%a" is valid+-- * "%a @c" is valid+-- * "%a %b @c @d" is valid+-- * "@c @d %a %b" is valid+-- * "@c %a %b @d" is not valid, because the two var anns are not "grouped" together.+-- * "%a @c @d %b" is not valid, because the two fields anns are not "grouped" together.+notesVVFF :: Parser ((VarAnn, VarAnn), (FieldAnn, FieldAnn))+notesVVFF = permute2Def (liftA2 (,) note noteDef) (liftA2 (,) note noteDef) notesVF :: Parser (VarAnn, FieldAnn) notesVF = permute2Def note note
src/Michelson/Parser/Error.hs view
@@ -21,8 +21,7 @@ import Util.Positive data CustomParserException- = UnknownTypeException- | StringLiteralException StringLiteralParserException+ = StringLiteralException StringLiteralParserException | OddNumberBytesException | WrongTagArgs Natural Positive | WrongAccessArgs Natural Positive@@ -34,7 +33,6 @@ instance NFData CustomParserException instance ShowErrorComponent CustomParserException where- showErrorComponent UnknownTypeException = "unknown type" showErrorComponent (StringLiteralException e) = showErrorComponent e showErrorComponent OddNumberBytesException = "odd number bytes" showErrorComponent ExcessFieldAnnotation = "excess field annotation"
src/Michelson/Parser/Ext.hs view
@@ -14,7 +14,7 @@ import Prelude hiding (try) -import Text.Megaparsec (choice, satisfy, try)+import Text.Megaparsec (choice, label, satisfy, try) import Text.Megaparsec.Char (alphaNumChar, string) import qualified Text.Megaparsec.Char.Lexer as L @@ -25,7 +25,7 @@ import qualified Michelson.Untyped as U extInstr :: Parser [ParsedOp] -> Parser ParsedUExtInstr-extInstr opsParser = choice [stackOp, testAssertOp opsParser, printOp]+extInstr opsParser = label "morley instruction" $ choice [stackOp, testAssertOp opsParser, printOp] stackOp :: Parser ParsedUExtInstr stackOp = word' "STACKTYPE" U.STACKTYPE <*> stackType
src/Michelson/Parser/Instr.hs view
@@ -10,6 +10,7 @@ -- * These are handled separately to have better error messages , mapOp , pairOp+ , unpairOp , pairNOp , cmpOp , dupOp@@ -19,7 +20,7 @@ import Prelude hiding (EQ, GT, LT, many, note, some, try) -import Text.Megaparsec (choice, notFollowedBy, sepEndBy, try)+import Text.Megaparsec (choice, label, notFollowedBy, sepEndBy, try) import qualified Text.Megaparsec.Char.Lexer as L import Michelson.Let (LetValue(..))@@ -33,7 +34,7 @@ -- | Parser for primitive Michelson instruction (no macros and extensions). primInstr :: Parser (Contract' ParsedOp) -> Parser ParsedOp -> Parser ParsedInstr-primInstr contractParser opParser = choice+primInstr contractParser opParser = label "primitive instruction" $ choice [ dropOp, swapOp, digOp, dugOp, pushOp opParser, someOp, noneOp, unitOp , ifNoneOp opParser, leftOp, rightOp, ifLeftOp opParser, nilOp , consOp, ifConsOp opParser, sizeOp, emptySetOp, emptyMapOp, emptyBigMapOp, iterOp opParser@@ -47,6 +48,8 @@ , balanceOp, checkSigOp, sha256Op, sha512Op, blake2BOp, hashKeyOp, pairingCheckOp , sourceOp, senderOp, chainIdOp, sha3Op, keccakOp, neverOp , votingPowerOp, totalVotingPowerOp, try unpairNOp+ , unpairOp+ , ticketOp, readTicketOp, splitTicketOp, joinTicketsOp ] -- | Parse a sequence of instructions.@@ -203,11 +206,26 @@ -- Operations on pairs pairOp :: Parser ParsedInstr pairOp = do- symbol' "PAIR";- (t, v, (p, q)) <- notesTVF2;+ symbol' "PAIR"+ (t, v, (p, q)) <- notesTVF2Def++ -- Make sure this is a `PAIR` instruction,+ -- and not a `PAIR n` instruction. notFollowedBy (lexeme L.decimal :: Parser Word)+ return $ PAIR t v p q +unpairOp :: Parser ParsedInstr+unpairOp = do+ symbol' "UNPAIR"+ ((vn1, vn2), (fn1, fn2)) <- notesVVFF++ -- Make sure this is an `UNPAIR` instruction,+ -- and not an `UNPAIR n` instruction.+ notFollowedBy (lexeme L.decimal :: Parser Word)++ return $ UNPAIR vn1 vn2 fn1 fn2+ pairNOp :: Parser ParsedInstr pairNOp = do symbol' "PAIR"@@ -294,8 +312,6 @@ -- Operations on unions --- Using `notesTVF2Def` instead of `notesTVF2` allows for the second annotation--- to be unspecified. leftOp :: Parser ParsedInstr leftOp = do symbol' "LEFT"; (t, v, (f, f')) <- notesTVF2Def; LEFT t v f f' <$> type_@@ -411,3 +427,17 @@ intOp :: Parser ParsedInstr intOp = word' "INT" INT <*> noteDef++-- Ticket Operations++ticketOp :: Parser ParsedInstr+ticketOp = word' "TICKET" TICKET <*> noteDef++readTicketOp :: Parser ParsedInstr+readTicketOp = word' "READ_TICKET" READ_TICKET <*> noteDef++splitTicketOp :: Parser ParsedInstr+splitTicketOp = word' "SPLIT_TICKET" SPLIT_TICKET <*> noteDef++joinTicketsOp :: Parser ParsedInstr+joinTicketsOp = word' "JOIN_TICKETS" JOIN_TICKETS <*> noteDef
src/Michelson/Parser/Let.hs view
@@ -53,7 +53,7 @@ semicolon local (addLet l) (letInner opParser) <|> return (addLet l env) --- | add a Let to the environment in the correct place+-- | Add a Let to the environment in the correct place addLet :: Let -> LetEnv -> LetEnv addLet l (LetEnv lms lvs lts) = case l of LetM lm -> LetEnv (Map.insert (lmName lm) lm lms) lvs lts@@ -67,10 +67,12 @@ , (LetT <$> letType) ] --- | build a let name parser from a leading character parser+-- | Build a let name parser from a leading character parser letName :: Parser Char -> Parser Text letName p = lexeme $ do v <- p+ -- FIXME (#557): It is possible to define a let name such as "add3", but then+ -- the parser doesn't recognize when it's used as an instruction. let validChar x = Char.isAscii x && (Char.isAlphaNum x || x == '\'' || x == '_') vs <- many (satisfy validChar) return $ toText (v:vs)
src/Michelson/Parser/Macro.hs view
@@ -18,10 +18,10 @@ import Prelude hiding (note, try) -import Text.Megaparsec (customFailure, notFollowedBy, try)+import Text.Megaparsec (customFailure, label, notFollowedBy, skipMany, try) import Text.Megaparsec.Char.Lexer (decimal) -import Michelson.Macro (CadrStruct(..), Macro(..), PairStruct(..), UnpairStruct(..), ParsedOp(..))+import Michelson.Macro (CadrStruct(..), Macro(..), PairStruct(..), ParsedOp(..), UnpairStruct(..)) import qualified Michelson.Macro as Macro import Michelson.Parser.Annotations import Michelson.Parser.Error@@ -35,8 +35,8 @@ import Util.Positive macro :: Parser ParsedOp -> Parser Macro-macro opParser =- word' "CASE" CASE <*> someNE ops+macro opParser = label "macro"+ $ word' "CASE" CASE <*> someNE ops <|> symbol' "TAG" *> tagMac <|> symbol' "ACCESS" *> accessMac <|> symbol' "SET " *> setMac@@ -81,25 +81,20 @@ let ps = Macro.mapPairLeaves fns a return $ PAPAIR ps tn vn -upairMacInner :: Parser UnpairStruct-upairMacInner = do+unpairMacInner :: Parser UnpairStruct+unpairMacInner = do string' "P"- l <- (string' "A" $> UF (noAnn, noAnn)) <|> upairMacInner- r <- (string' "I" $> UF (noAnn, noAnn)) <|> upairMacInner+ l <- (string' "A" $> UF) <|> unpairMacInner+ r <- (string' "I" $> UF) <|> unpairMacInner return $ UP l r unpairMac :: Parser Macro unpairMac = do string' "UN"- a <- upairMacInner+ a <- unpairMacInner symbol' "R"- (vns, fns) <- permute2Def (some note) (some note)- return $ UNPAIR (Macro.mapUnpairLeaves (padAnnotations vns fns) a)- where- padAnnotations [] [] = []- padAnnotations [] (f : fs) = (noAnn, f) : padAnnotations [] fs- padAnnotations (v : vs) [] = (v, noAnn) : padAnnotations vs []- padAnnotations (v : vs) (f : fs) = (v, f ) : padAnnotations vs fs+ skipMany $ (void noteF) <|> (void noteV)+ return $ UNPAPAIR a cadrMac :: Parser Macro cadrMac = lexeme $ do
src/Michelson/Parser/Type.hs view
@@ -15,7 +15,7 @@ import Data.Default (Default, def) import qualified Data.Map as Map import Fmt (pretty)-import Text.Megaparsec (choice, customFailure, sepBy)+import Text.Megaparsec (choice, customFailure, label, sepBy) import Michelson.Let (LetType(..)) import Michelson.Parser.Annotations@@ -65,17 +65,16 @@ typeInner :: Parser FieldAnn -> Parser (FieldAnn, Ty)-typeInner fp = lexeme $ choice $ (\x -> x fp) <$>+typeInner fp = label "type" $ lexeme $ choice $ (\x -> x fp) <$> [ t_int, t_nat, t_string, t_bytes, t_mutez, t_bool , t_keyhash, t_timestamp, t_address , t_key, t_unit, t_never, t_signature, t_chain_id , t_bls12381fr, t_bls12381g1, t_bls12381g2 , t_option, t_list, t_set- , t_operation, t_contract, t_pair, t_or+ , t_operation, t_contract, t_ticket, t_pair, t_or , t_lambda, t_map, t_big_map, t_view , t_void, t_letType , t_operator- , const (customFailure UnknownTypeException) ] ----------------------------------------------------------------------------@@ -155,6 +154,13 @@ (f, t) <- fieldType fp a <- type_ return (f, Ty (TContract a) t)++t_ticket :: (Default a) => Parser a -> Parser (a, Ty)+t_ticket fp = do+ symbol' "Ticket"+ (f, t) <- fieldType fp+ a <- type_+ return (f, Ty (TTicket a) t) t_unit :: (Default a) => Parser a -> Parser (a, Ty) t_unit fp = do
src/Michelson/Parser/Value.hs view
@@ -20,7 +20,7 @@ import qualified Data.Map as Map import qualified Text.Hex as Hex -import Text.Megaparsec (anySingle, choice, customFailure, manyTill, satisfy, takeWhileP, try)+import Text.Megaparsec (anySingle, choice, customFailure, label, manyTill, satisfy, takeWhileP, try) import Text.Megaparsec.Char (char, string) import qualified Text.Megaparsec.Char.Lexer as L @@ -30,7 +30,7 @@ import Michelson.Parser.Helpers import Michelson.Parser.Lexer import Michelson.Parser.Types (Parser, letValues)-import Michelson.Text (isMChar, mkMTextUnsafe)+import Michelson.Text (isMChar, unsafeMkMText) import qualified Michelson.Untyped as U -- | Parse untyped 'ParsedValue'. Take instruction parser as argument@@ -41,7 +41,7 @@ valueInner' = valueInner opParser valueInner :: Parser ParsedOp -> Parser ParsedValue-valueInner opParser = choice $+valueInner opParser = label "value" $ choice $ [ stringLiteral, bytesLiteral, intLiteral, unitValue , trueValue, falseValue, pairValue opParser, leftValue opParser , rightValue opParser, someValue opParser, noneValue, nilValue@@ -52,7 +52,7 @@ seqOrLambda opParser = try (lambdaValue opParser) <|> seqValue opParser stringLiteral :: Parser ParsedValue-stringLiteral = U.ValueString . mkMTextUnsafe . toText <$> do+stringLiteral = U.ValueString . unsafeMkMText . toText <$> do _ <- try $ string "\"" manyTill validChar (string "\"") where
src/Michelson/Preprocess.hs view
@@ -42,12 +42,12 @@ forall inp out. Bool -> (forall t. Value t -> Value t)- -- ^ Should transform only atomic values, 'dfsValue' will be applied to it.+ -- ^ Should transform only atomic values, 'dfsMapValue' will be applied to it. -> Instr inp out -> Instr inp out transformConstants dsGoToValues f = fst . dfsInstr def{ dsGoToValues } step where step :: forall i o. Instr i o -> (Instr i o, ()) step = (,()) . \case- PUSH v -> PUSH (dfsModifyValue f v)+ PUSH v -> PUSH (dfsMapValue f v) i -> i
src/Michelson/Printer.hs view
@@ -4,6 +4,7 @@ module Michelson.Printer ( RenderDoc(..)+ , renderAnyBuildable , printDoc , printUntypedContract , printTypedContractCode@@ -17,8 +18,7 @@ import Data.Singletons (SingI) import qualified Data.Text.Lazy as TL -import Michelson.Printer.Util (RenderDoc(..), doesntNeedParens, printDoc)-import Michelson.TypeCheck.Types (SomeContract(..))+import Michelson.Printer.Util (RenderDoc(..), renderAnyBuildable, doesntNeedParens, printDoc) import qualified Michelson.Typed as T import qualified Michelson.Untyped as U @@ -57,6 +57,6 @@ -- | Convert 'SomeContract' into a textual representation which -- will be accepted by the OCaml reference client.-printSomeContract :: Bool -> SomeContract -> TL.Text-printSomeContract forceSingleLine (SomeContract fc) =+printSomeContract :: Bool -> T.SomeContract -> TL.Text+printSomeContract forceSingleLine (T.SomeContract fc) = printTypedContract forceSingleLine fc
src/Michelson/Printer/Util.hs view
@@ -11,9 +11,12 @@ , renderOps , renderOpsList , renderOpsListNoBraces+ , renderAnyBuildable , spaces , wrapInParens , buildRenderDoc+ , buildRenderDocExtended+ , renderDocList -- * Smart parentheses , RenderContext@@ -23,12 +26,13 @@ , assertParensNotNeeded ) where +import Fmt (Buildable, pretty) import Control.Exception (assert) import qualified Data.Text.Lazy as LT import Data.Text.Lazy.Builder (Builder) import Text.PrettyPrint.Leijen.Text (Doc, SimpleDoc, align, braces, displayB, displayT, enclose, hcat, isEmpty, parens, punctuate,- renderOneLine, renderPretty, semi, space, vcat, (<+>))+ renderOneLine, renderPretty, semi, space, text, vcat, (<+>), lbracket, rbracket, encloseSep) -- | Environment carried during recursive rendering. newtype RenderContext = RenderContext@@ -55,6 +59,14 @@ isRenderable :: a -> Bool isRenderable _ = True +-- | Renders a list of 'RenderDoc' elements surrounded with square brackets,+-- separated by a comma and a space.+renderDocList :: RenderDoc a => RenderContext -> [a] -> Doc+renderDocList context = encloseSep lbracket rbracket ", " . fmap (renderDoc context)++renderAnyBuildable :: Buildable a => a -> Doc+renderAnyBuildable = text . pretty+ -- | A new type that can wrap values so that the RenderDoc -- instances of the combined value can have a different -- behavior for the pretty printer.@@ -106,6 +118,11 @@ -- It's formatted the same way as `printDoc` formats docs. buildRenderDoc :: RenderDoc a => a -> Builder buildRenderDoc = printDocB True . renderDoc doesntNeedParens++-- | Works as 'buildRenderDoc' above, but doesn't force the doc to be printed in one line+buildRenderDocExtended :: RenderDoc a => a -> Builder+buildRenderDocExtended = printDocB False . renderDoc doesntNeedParens+ -- | Here using a page width of 80 and a ribbon width of 1.0 -- https://hackage.haskell.org/package/wl-pprint-1.2.1/docs/Text-PrettyPrint-Leijen.html
src/Michelson/Runtime.hs view
@@ -56,29 +56,28 @@ import Data.Text.IO (getContents) import qualified Data.Text.IO.Utf8 as Utf8 (readFile) import Fmt (Buildable(build), blockListF, fmt, fmtLn, nameF, pretty, (+|), (|+))-import Named ((:!), (:?), arg, argDef, defaults, (!))+import Named (arg, argDef, defaults, (!), (:!), (:?)) import Text.Megaparsec (parse) -import Data.Singletons (demote)-import Data.Typeable (gcast) import Michelson.Interpret (ContractEnv(..), InterpretError(..), InterpretResult(..), InterpreterState(..), MorleyLogs(..),- RemainingSteps(..), handleContractReturn, interpret)+ RemainingSteps(..), assignBigMapIds, handleContractReturn, interpret) import qualified Michelson.Interpret.Pack as Pack import Michelson.Macro (ParsedOp, expandContract) import qualified Michelson.Parser as P import Michelson.Runtime.GState import Michelson.Runtime.TxData import Michelson.TypeCheck- (SomeContractAndStorage(..), TCError, typeCheckContractAndStorage, typeVerifyParameter) import Michelson.Typed (CreateContract(..), EntrypointCallT, EpAddress(..), EpName, Operation'(..), ParameterScope,- SomeValue'(..), TransferTokens(..), starNotes, starParamNotes, untypeValue)+ SomeContractAndStorage(..), SomeStorage(..), SomeValue(..), TransferTokens(..), starNotes,+ starParamNotes, untypeValue) import qualified Michelson.Typed as T-import Michelson.Typed.Origination (OriginationOperation(..), mkOriginationOperationHash)-import Michelson.Untyped (Contract, OperationHash(..))+import Michelson.Typed.Origination+ (OperationHash(..), OriginationOperation(..), mkContractAddress, mkOriginationOperationHash)+import Michelson.Untyped (Contract) import qualified Michelson.Untyped as U-import Tezos.Address (Address(..), OriginationIndex(..), mkContractAddress)+import Tezos.Address (Address(..), OriginationIndex(..)) import Tezos.Core (Mutez, Timestamp(..), getCurrentTime, unMutez, unsafeAddMutez, unsafeSubMutez, zeroMutez) import Tezos.Crypto (KeyHash, blake2b, parseKeyHash)@@ -167,15 +166,17 @@ -- ^ Sending 0tz towards an address. | EEFailedToApplyUpdates GStateUpdateError -- ^ Failed to apply updates to GState.- | EEIllTypedParameter TCError+ | EEIllTypedParameter a TCError -- ^ Contract parameter is ill-typed.- | EEUnexpectedParameterType T.T T.T+ | EEUnexpectedParameterType a T.T T.T -- ^ Contract parameter is well-typed, but its type does -- not match the entrypoint's type. | EEUnknownEntrypoint EpName -- ^ Specified entrypoint to run is not found. | EETransactionFromContract a Mutez -- ^ A transaction from an originated contract was attempted as a global operation.+ | EEWrongParameterType a+ -- ^ Type of parameter in transfer to an implicit account is not Unit. deriving stock (Show, Functor) instance (Buildable a) => Buildable (ExecutorError' a) where@@ -195,14 +196,16 @@ EEZeroTransaction addr -> "Transaction of 0ꜩ towards a key address " +| addr |+ " which has no code is prohibited" EEFailedToApplyUpdates err -> "Failed to update GState: " +| err |+ ""- EEIllTypedParameter err -> "The contract parameter is ill-typed: " +| err |+ ""- EEUnexpectedParameterType expectedT actualT ->+ EEIllTypedParameter _ err -> "The contract parameter is ill-typed: " +| err |+ ""+ EEUnexpectedParameterType _ actualT expectedT -> "The contract parameter is well-typed, but did not match the contract's entrypoint's type.\n" <> "Expected: " +| expectedT |+ "\n" <> "Got: " +| actualT |+ "" EEUnknownEntrypoint epName -> "The contract does not contain entrypoint '" +| epName |+ "'" EETransactionFromContract addr amount -> "Global transaction of funds (" +| amount |+ ") from an originated contract (" +| addr |+ ") is prohibited."+ EEWrongParameterType addr ->+ "Bad contract parameter for: " +| addr |+ "" type ExecutorError = ExecutorError' Address @@ -243,6 +246,7 @@ -- contract. originateContract :: FilePath+ -> TypeCheckOptions -> Address -> Maybe KeyHash -> Mutez@@ -250,8 +254,8 @@ -> U.Contract -> "verbose" :! Bool -> IO Address-originateContract dbPath originator delegate balance uStorage uContract verbose = do- origination <- either throwM pure $+originateContract dbPath tcOpts originator delegate balance uStorage uContract verbose = do+ origination <- either throwM pure . typeCheckingWith tcOpts $ mkOrigination <$> typeCheckContractAndStorage uContract uStorage -- pass 100500 as maxSteps, because it doesn't matter for origination, -- as well as 'now'@@ -274,22 +278,23 @@ -> Word64 -> Mutez -> FilePath+ -> TypeCheckOptions -> U.Value -> U.Contract -> TxData -> "verbose" :! Bool -> "dryRun" :! Bool- -> IO U.Value-runContract maybeNow maybeLevel maxSteps initBalance dbPath uStorage uContract txData+ -> IO SomeStorage+runContract maybeNow maybeLevel maxSteps initBalance dbPath tcOpts uStorage uContract txData verbose (arg #dryRun -> dryRun) = do- origination <- either throwM pure $+ origination <- either throwM pure . typeCheckingWith tcOpts $ mkOrigination <$> typeCheckContractAndStorage uContract uStorage (_, newSt) <- runExecutorMWithDB maybeNow maybeLevel dbPath (RemainingSteps maxSteps) verbose ! #dryRun dryRun $ do -- Here we are safe to bypass executeGlobalOperations for origination, -- since origination can't generate more operations. addr <- executeGlobalOrigination origination let transferOp = TransferOp addr txData- executeGlobalOperations [transferOp]+ executeGlobalOperations tcOpts [transferOp] getContractStorage addr return newSt where@@ -309,13 +314,13 @@ , ooContract = contract } - getContractStorage :: Address -> ExecutorM U.Value+ getContractStorage :: Address -> ExecutorM SomeStorage getContractStorage addr = do addrs <- use (esGState . gsAddressesL) case addrs ^. at addr of Nothing -> error $ pretty addr <> " is unknown" Just (ASSimple {}) -> error $ pretty addr <> " is a simple address"- Just (ASContract (ContractState{..})) -> return $ untypeValue csStorage+ Just (ASContract (ContractState{..})) -> return $ SomeStorage csStorage -- | Send a transaction to given address with given parameters. transfer ::@@ -323,14 +328,15 @@ -> Maybe Natural -> Word64 -> FilePath+ -> TypeCheckOptions -> Address -> TxData -> "verbose" :! Bool -> "dryRun" :? Bool -> IO ()-transfer maybeNow maybeLevel maxSteps dbPath destination txData verbose dryRun = do+transfer maybeNow maybeLevel maxSteps dbPath tcOpts destination txData verbose dryRun = do void $ runExecutorMWithDB maybeNow maybeLevel dbPath (RemainingSteps maxSteps) verbose dryRun $- executeGlobalOperations [TransferOp destination txData]+ executeGlobalOperations tcOpts [TransferOp destination txData] ---------------------------------------------------------------------------- -- Executor@@ -432,9 +438,10 @@ -- | Execute a list of global operations, discarding their results. executeGlobalOperations- :: [ExecutorOp]+ :: TypeCheckOptions+ -> [ExecutorOp] -> ExecutorM ()-executeGlobalOperations = mapM_ $ \op ->+executeGlobalOperations tcOpts = mapM_ $ \op -> executeMany (#isGlobalOp .! True) [op] where -- | Execute a list of operations and additional operations they return, until there are none.@@ -445,8 +452,8 @@ case op of OriginateOp origination -> void $ executeOrigination isGlobalOp origination TransferOp addr txData -> do- moreOps <- executeTransfer isGlobalOp addr txData- executeMany (#isGlobalOp .! False) $ opsTail <> moreOps+ moreOps <- executeTransfer isGlobalOp tcOpts addr txData+ executeMany (#isGlobalOp .! False) $ moreOps <> opsTail -- | Execute a global origination operation. executeGlobalOrigination :: OriginationOperation -> ExecutorM Address@@ -457,7 +464,7 @@ :: "isGlobalOp" :! Bool -> OriginationOperation -> ExecutorM Address-executeOrigination (arg #isGlobalOp -> isGlobalOp) origination = do+executeOrigination (arg #isGlobalOp -> isGlobalOp) origination@(OriginationOperation _ _ bal st contract) = do when isGlobalOp $ do beginGlobalOperation assign esOperationHash $ mkOriginationOperationHash origination@@ -466,9 +473,13 @@ gs <- use esGState originationNonce <- use esOriginationNonce- let contractState =- case origination of- OriginationOperation _ _ bal st contract -> ContractState bal contract st++ -- Add big_map IDS to storage+ let bigMapCounter0 = gs ^. gsBigMapCounterL+ let (storageWithIds, bigMapCounter1) = runState (assignBigMapIds st) bigMapCounter0++ let contractState = ContractState bal contract storageWithIds+ let originatorAddress = ooOriginator origination originatorBalance <- case gsAddresses gs ^. at originatorAddress of Nothing -> throwError (EEUnknownManager originatorAddress)@@ -482,10 +493,15 @@ let address = mkContractAddress opHash (OriginationIndex originationNonce) (gsCounter gs) updates =- [ GSAddAddress address (ASContract contractState)- , GSSetBalance originatorAddress originatorBalance- , GSIncrementCounter- ]+ catMaybes+ [ Just $ GSAddAddress address (ASContract contractState)+ , Just $ GSSetBalance originatorAddress originatorBalance+ , Just $ GSIncrementCounter+ , if bigMapCounter0 == bigMapCounter1+ then Nothing+ else Just $ GSSetBigMapCounter bigMapCounter1+ ]+ case applyUpdates updates gs of Left _ -> throwError $ EEAlreadyOriginated address contractState@@ -500,10 +516,11 @@ -- | Execute a transfer operation. executeTransfer :: "isGlobalOp" :! Bool+ -> TypeCheckOptions -> Address -> TxData -> ExecutorM [ExecutorOp]-executeTransfer (arg #isGlobalOp -> isGlobalOp) addr txData = do+executeTransfer (arg #isGlobalOp -> isGlobalOp) tcOpts addr txData = do when isGlobalOp $ beginGlobalOperation @@ -520,6 +537,9 @@ isKeyAddress _ = False let isZeroTransfer = tdAmount txData == zeroMutez + when (badParamToImplicitAccount addr $ tdParameter txData) $+ throwError $ EEWrongParameterType addr+ -- Transferring 0 XTZ to a key address is prohibited. when (isZeroTransfer && isKeyAddress addr) $ throwError $ EEZeroTransaction addr@@ -571,13 +591,15 @@ -- we need to typecheck the parameter. typedParameter <- case tdParameter txData of- TxTypedParam (typedVal :: T.Value t) ->- maybe (throwError $ EEUnexpectedParameterType (demote @epArg) (demote @t)) pure $- gcast @t @epArg typedVal+ TxTypedParam (typedVal :: T.Value t) -> do+ T.castM @t @epArg typedVal (throwError ... EEUnexpectedParameterType addr) TxUntypedParam untypedVal ->- liftEither $ first EEIllTypedParameter $+ liftEither $ first (EEIllTypedParameter addr) $ typeCheckingWith tcOpts $ typeVerifyParameter @epArg existingContracts untypedVal + let bigMapCounter0 = gs ^. gsBigMapCounterL+ let (typedParameterWithIds, bigMapCounter1) = runState (assignBigMapIds typedParameter) bigMapCounter0+ -- I'm not entirely sure why we need to pattern match on `()` here, -- but, if we don't, we get a compiler error that I suspect is somehow related -- to the existential types we're matching on a few lines above.@@ -588,7 +610,7 @@ () <- when isGlobalOp $ esOperationHash .= mkTransferOperationHash addr- typedParameter+ typedParameterWithIds (tdEntrypoint txData) (tdAmount txData) @@ -613,12 +635,17 @@ iur@InterpretResult { iurOps = sideEffects , iurNewStorage = newValue- , iurNewState = InterpreterState _ newRemainingSteps _+ , iurNewState = InterpreterState _ newRemainingSteps _ bigMapCounter2 } <- liftEither $ first (EEInterpreterFailed addr) $ handleContractReturn $- interpret csContract epc- typedParameter csStorage contractEnv+ interpret+ csContract+ epc+ typedParameterWithIds+ csStorage+ bigMapCounter1+ contractEnv let updBalance | newBalance == csBalance = Nothing@@ -626,9 +653,13 @@ updStorage | SomeValue newValue == SomeValue csStorage = Nothing | otherwise = Just $ GSSetStorageValue addr newValue+ updBigMapCounter+ | bigMapCounter0 == bigMapCounter2 = Nothing+ | otherwise = Just $ GSSetBigMapCounter bigMapCounter2 updates = catMaybes [ updBalance , updStorage+ , updBigMapCounter ] return (updates, sideEffects, Just iur, newRemainingSteps) @@ -661,8 +692,8 @@ packedOperation = BSL.toStrict $ (runPut $ putWord64be $ unMutez amount)- <> Pack.encodeEpAddress (EpAddress to epName)- <> Pack.encodeValue param+ <> (Pack.toBinary $ T.toVal (EpAddress to epName))+ <> Pack.toBinary param -- The argument is the address of the contract that generated this operation. convertOp :: Address -> T.Operation -> Maybe ExecutorOp@@ -701,3 +732,10 @@ beginGlobalOperation = do esOriginationNonce .= 0 esSourceAddress .= Nothing++-- | Return True if address is an implicit account yet the param is not Unit.+badParamToImplicitAccount :: Address -> TxParam -> Bool+badParamToImplicitAccount (ContractAddress _) _ = False+badParamToImplicitAccount (KeyAddress _) (TxTypedParam T.VUnit) = False+badParamToImplicitAccount (KeyAddress _) (TxUntypedParam U.ValueUnit) = False+badParamToImplicitAccount _ _ = True
src/Michelson/Runtime/Dummy.hs view
@@ -9,12 +9,13 @@ , dummyLevel , dummyMaxSteps , dummyVotingPowers+ , dummyBigMapCounter , dummyContractEnv , dummyOrigination ) where import Michelson.Interpret (ContractEnv(..), RemainingSteps)-import Michelson.Runtime.GState (dummyVotingPowers, genesisAddress)+import Michelson.Runtime.GState (BigMapCounter, dummyVotingPowers, genesisAddress) import Michelson.Typed (ParameterScope, StorageScope) import qualified Michelson.Typed as T import Michelson.Typed.Origination (OriginationOperation(..))@@ -35,6 +36,9 @@ -- interpreter from working for eternity. dummyMaxSteps :: RemainingSteps dummyMaxSteps = 100500++dummyBigMapCounter :: BigMapCounter+dummyBigMapCounter = 0 -- | Dummy 'ContractEnv' with some reasonable hardcoded values. You -- can override values you are interested in using record update
src/Michelson/Runtime/GState.hs view
@@ -16,6 +16,8 @@ , mkVotingPowers , mkVotingPowersFromMap , dummyVotingPowers+ , BigMapCounter(..)+ , bigMapCounter -- * GState , GState (..)@@ -23,6 +25,7 @@ , gsAddressesL , gsVotingPowersL , gsCounterL+ , gsBigMapCounterL , genesisAddresses , genesisKeyHashes , genesisAddress@@ -50,22 +53,24 @@ , extractAllContracts ) where -import Control.Lens (at)+import Control.Lens (at, makeLenses) import Data.Aeson (FromJSON(..), ToJSON(..), object, withObject, (.:), (.=)) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encode.Pretty as Aeson import Data.Aeson.TH (deriveJSON) import qualified Data.ByteString.Lazy as LBS+import Data.Default (def) import Data.List.NonEmpty ((!!)) import qualified Data.Map.Strict as Map-import Data.Typeable ((:~:)(..), eqT)+import Data.Type.Equality ((:~:)(..)) import Fmt (Buildable(build), (+|), (|+), (||+)) import System.IO.Error (IOError, isDoesNotExistError) import Michelson.TypeCheck- (SomeContractAndStorage(..), SomeParamType(..), TcOriginatedContracts,- typeCheckContractAndStorage)+ (SomeParamType(..), TcOriginatedContracts,+ typeCheckContractAndStorage, typeCheckingWith) import qualified Michelson.Typed as T+import Michelson.Typed.Existential (SomeContractAndStorage(..)) import Michelson.Typed.Scope import Michelson.Untyped (Contract, Value) import Tezos.Address (Address(..), ContractHash, GlobalCounter(..))@@ -73,6 +78,7 @@ import Tezos.Crypto import Util.Aeson import Util.Lens+import Util.Sing (eqI) -- | State of a contract with code. data ContractState =@@ -104,7 +110,7 @@ (balance :: Mutez) <- o .: "balance" (uStorage :: Value) <- o .: "storage" (uContract :: Contract) <- o .: "contract"- case typeCheckContractAndStorage uContract uStorage of+ case typeCheckingWith def $ typeCheckContractAndStorage uContract uStorage of Right (SomeContractAndStorage contract storage) -> pure $ ContractState balance contract storage Left err -> fail $ "Unable to parse `ContractState`: " <> (show err)@@ -170,6 +176,17 @@ mkVotingPowers :: [(KeyHash, Natural)] -> VotingPowers mkVotingPowers = mkVotingPowersFromMap . Map.fromListWith (+) +-- | All big_maps stored in a chain have a globally unique ID.+--+-- We use this counter to keep track of how many big_maps have been created so far,+-- and to generate new IDs whenever a new big_map is created.+newtype BigMapCounter = BigMapCounter { _bigMapCounter :: Natural }+ deriving stock (Show, Eq, Generic)+ deriving anyclass (NFData)+ deriving newtype (ToJSON, FromJSON, Num, Buildable)++makeLenses ''BigMapCounter+ -- | Persistent data passed to Morley contracts which can be updated -- as result of contract execution. data GState = GState@@ -181,6 +198,7 @@ -- ^ Voting power distribution. , gsCounter :: GlobalCounter -- ^ Ever increasing operation counter.+ , gsBigMapCounter :: BigMapCounter } deriving stock (Show) makeLensesWith postfixLFields ''GState@@ -252,6 +270,7 @@ ] , gsVotingPowers = dummyVotingPowers , gsCounter = GlobalCounter 0+ , gsBigMapCounter = BigMapCounter 0 } data GStateParseError =@@ -290,6 +309,7 @@ GSSetStorageValue :: StorageScope st => Address -> T.Value st -> GStateUpdate GSSetBalance :: Address -> Mutez -> GStateUpdate GSIncrementCounter :: GStateUpdate+ GSSetBigMapCounter :: BigMapCounter -> GStateUpdate deriving stock instance Show GStateUpdate @@ -304,6 +324,8 @@ "Set balance of address " +| addr |+ " to " +| balance |+ "" GSIncrementCounter -> "Increment internal counter after operation"+ GSSetBigMapCounter inc ->+ "Increment internal big_map counter by: " +| build inc data GStateUpdateError = GStateAddressExists Address@@ -332,6 +354,7 @@ setStorageValue addr newValue GSSetBalance addr newBalance -> setBalance addr newBalance GSIncrementCounter -> Right . over gsCounterL (+1)+ GSSetBigMapCounter bmCounter -> Right . set gsBigMapCounterL bmCounter -- | Apply a list of 'GStateUpdate's to 'GState'. applyUpdates :: [GStateUpdate] -> GState -> Either GStateUpdateError GState@@ -353,7 +376,7 @@ modifier :: AddressState -> Either GStateUpdateError AddressState modifier (ASSimple _) = Left (GStateNotContract addr) modifier (ASContract (ContractState b c (_ :: T.Value st') )) = do- case (eqT @st @st') of+ case eqI @st @st' of Just Refl -> Right $ ASContract $ ContractState b c newValue _ -> Left $ GStateStorageNotMatch addr
+ src/Michelson/Runtime/Import.hs view
@@ -0,0 +1,205 @@+-- SPDX-FileCopyrightText: 2020 Tocqueville Group+--+-- SPDX-License-Identifier: LicenseRef-MIT-TQ++module Michelson.Runtime.Import+ (+ -- * Read, parse, typecheck contract+ readContract+ , readSomeContract+ , readUntypedContract+ , importContract+ , importSomeContract+ , importUntypedContract+ , ImportContractError(..)++ -- * Read, parse, typecheck value+ , readValue+ , importValue+ , importSomeValue+ , importUntypedValue+ , ImportValueError (..)++ -- * Generic helpers+ , importUsing+ ) where++import Data.Default (def)+import qualified Data.Text.IO.Utf8 as Utf8 (readFile)+import Fmt (Buildable(build), pretty, unlinesF, (+|), (|+))++import Michelson.Parser (parseExpandValueFromFile)+import Michelson.Parser.Error (ParserException(..))+import Michelson.Runtime (parseExpandContract)+import Michelson.TypeCheck+ (TCError, typeCheckContract, typeCheckTopLevelType, typeCheckingWith,+ typeVerifyContract, typeVerifyTopLevelType)+import Michelson.Typed (Contract(..), SingI, SomeContract(..), SomeValue, Value)+import qualified Michelson.Untyped as U++----------------------------------------------------------------------------+-- Reading, parsing, typechecking contract+----------------------------------------------------------------------------++-- | Purely read an untyped contract from Michelson textual representation.+--+-- 'FilePath' is accepted solely as a hint for error messages.+readUntypedContract+ :: FilePath+ -> Text+ -> Either ImportContractError U.Contract+readUntypedContract filePath txt = do+ first (ICEParse filePath) $ parseExpandContract (Just filePath) txt++-- | Purely read a typed contract from Michelson textual representation.+readSomeContract+ :: FilePath+ -> Text+ -> Either ImportContractError SomeContract+readSomeContract filePath txt = do+ contract <- readUntypedContract filePath txt+ first (ICETypeCheck filePath) $+ typeCheckingWith def $ typeCheckContract contract++-- | Purely read a typed contract from Michelson textual representation,+-- failing if parameter or storage types mismatch with the expected ones.+readContract+ :: forall cp st .+ Each '[SingI] [cp, st]+ => FilePath+ -> Text+ -> Either ImportContractError (Contract cp st)+readContract filePath txt = do+ contract <- readUntypedContract filePath txt+ first (ICETypeCheck filePath) $+ typeCheckingWith def $ typeVerifyContract contract++-- | Read a thing from a file, using the provided parsing function.+importUsing+ :: (Exception e)+ => (FilePath -> Text -> Either e a)+ -> FilePath -> IO a+importUsing readFn file =+ either throwM pure . readFn file =<< Utf8.readFile file++-- | Import untyped contract from a given file path.+--+-- This function reads file, and parses a contract.+--+-- This function may throw 'IOException' and 'ImportContractError'.+importUntypedContract :: FilePath -> IO U.Contract+importUntypedContract = importUsing readUntypedContract++-- | Import contract from a given file path.+--+-- This function reads file, parses and type checks a contract.+-- Within the typechecking we assume that no contracts are originated,+-- otherwise a type checking error will be caused.+--+-- This function may throw 'IOException' and 'ImportContractError'.+importContract+ :: forall cp st .+ Each '[SingI] [cp, st]+ => FilePath -> IO (Contract cp st)+importContract = importUsing readContract++-- | Version of 'importContract' that doesn't require you to know+-- contract's parameter and storage types.+importSomeContract :: FilePath -> IO SomeContract+importSomeContract = importUsing readSomeContract++-- | Error type for 'importContract' function.+data ImportContractError+ = ICEParse FilePath ParserException+ | ICETypeCheck FilePath TCError+ deriving stock (Show, Eq)++instance Buildable ImportContractError where+ build =+ \case+ ICEParse filePath e -> unlinesF+ [ "Error at " <> build filePath+ , "Failed to parse the contract: " +| e |+ ""+ ]+ ICETypeCheck filePath e -> unlinesF+ [ "Error at " <> build filePath+ , "The contract is ill-typed: " +| e |+ ""+ ]++instance Exception ImportContractError where+ displayException = pretty++----------------------------------------------------------------------------+-- Reading, parsing, typechecking value+----------------------------------------------------------------------------++-- | Purely read an untyped Michelson value from textual representation.+--+-- 'FilePath' is accepted solely as a hint for error messages.+readUntypedValue+ :: FilePath+ -> Text+ -> Either ImportValueError U.Value+readUntypedValue filePath txt = do+ first (IVEParse filePath) $ parseExpandValueFromFile filePath txt++-- | Purely read a typed Michelson value from textual representation.+--+-- Expected type is provided explicitly.+readSomeValue+ :: U.Ty+ -> FilePath+ -> Text+ -> Either ImportValueError SomeValue+readSomeValue ty filePath txt = do+ valueU <- readUntypedValue filePath txt+ first (IVETypeCheck filePath) $+ typeCheckingWith def $ typeCheckTopLevelType Nothing ty valueU++-- | Purely read a typed Michelson value from textual representation.+readValue+ :: forall t. SingI t+ => FilePath+ -> Text+ -> Either ImportValueError (Value t)+readValue filePath txt = do+ valueU <- readUntypedValue filePath txt+ first (IVETypeCheck filePath) $+ typeCheckingWith def $ typeVerifyTopLevelType Nothing valueU++-- | Import an untyped value from a given file path.+importUntypedValue :: FilePath -> IO U.Value+importUntypedValue = importUsing readUntypedValue++-- | Import a typed value from a given file path.+--+-- Expected type is provided explicitly.+importSomeValue :: U.Ty -> FilePath -> IO SomeValue+importSomeValue = importUsing . readSomeValue++-- | Import a typed value from a given file path.+importValue+ :: forall t . SingI t+ => FilePath -> IO (Value t)+importValue = importUsing readValue++-- | Error type for 'importValue' function.+data ImportValueError+ = IVEParse FilePath ParserException+ | IVETypeCheck FilePath TCError+ deriving stock (Show, Eq)++instance Buildable ImportValueError where+ build =+ \case+ IVEParse filePath e -> unlinesF+ [ "Error at " <> build filePath+ , "Failed to parse the value: " +| e |+ ""+ ]+ IVETypeCheck filePath e -> unlinesF+ [ "Error at " <> build filePath+ , "The value is ill-typed: " +| e |+ ""+ ]++instance Exception ImportValueError where+ displayException = pretty
src/Michelson/Text.hs view
@@ -19,7 +19,7 @@ module Michelson.Text ( MText (..) , mkMText- , mkMTextUnsafe+ , unsafeMkMText , mkMTextCut , writeMText , takeMText@@ -61,16 +61,16 @@ -- * With QuasyQuotes when need to create a string literal. -- -- >>> [mt|Some text|]--- MTextUnsafe {unMText = "Some text"}+-- UnsafeMText {unMText = "Some text"} -- -- * With 'mkMText' when constructing from a runtime text value. ----- * With 'mkMTextUnsafe' or 'MTextUnsafe' when absolutelly sure that+-- * With 'unsafeMkMText' or 'UnsafeMText' when absolutelly sure that -- given string does not violate invariants. -- -- * With 'mkMTextCut' when not sure about text contents and want -- to make it compliant with Michelson constraints.-newtype MText = MTextUnsafe { unMText :: Text }+newtype MText = UnsafeMText { unMText :: Text } deriving stock (Show, Eq, Ord, Data, Generic) deriving newtype (Semigroup, Monoid, Container, Buildable, Hashable) @@ -93,7 +93,7 @@ -- You can use e.g. @'\n'@ character directly in supplied argument, -- but attempt to use other bad characters like @'\r'@ will cause failure. mkMText :: Text -> Either Text MText-mkMText txt = mapM checkMChar (toString txt) $> MTextUnsafe txt+mkMText txt = mapM checkMChar (toString txt) $> UnsafeMText txt where checkMChar c | isMChar c || c == '\n' = pass@@ -101,30 +101,30 @@ -- | Contruct 'MText' from a Haskell text, failing if provided Haskell text -- is invalid Michelson string.-mkMTextUnsafe :: HasCallStack => Text -> MText-mkMTextUnsafe = either error id . mkMText+unsafeMkMText :: HasCallStack => Text -> MText+unsafeMkMText = either error id . mkMText -- | Construct 'MText' from a Haskell text, eliminating all characters which -- should not appear in Michelson strings. -- Characters which can be displayed normally via escaping are preserved. mkMTextCut :: Text -> MText mkMTextCut txt =- MTextUnsafe . toText . filter isAllowed $ toString txt+ UnsafeMText . toText . filter isAllowed $ toString txt where isAllowed c = isMChar c || c == '\n' -- | Print 'MText' for Michelson code, with all unusual characters escaped. writeMText :: MText -> Text-writeMText (MTextUnsafe t) = t+writeMText (UnsafeMText t) = t & T.replace "\\" "\\\\" & T.replace "\n" "\\n" & T.replace "\"" "\\\"" takeMText :: Int -> MText -> MText-takeMText n (MTextUnsafe txt) = MTextUnsafe $ T.take n txt+takeMText n (UnsafeMText txt) = UnsafeMText $ T.take n txt dropMText :: Int -> MText -> MText-dropMText n (MTextUnsafe txt) = MTextUnsafe $ T.drop n txt+dropMText n (UnsafeMText txt) = UnsafeMText $ T.drop n txt instance ToText MText where toText = unMText@@ -159,11 +159,11 @@ { TH.quoteExp = \s -> case qqMText s of Left err -> fail $ toString err- Right txt -> [e| MTextUnsafe (toText @String txt) |]+ Right txt -> [e| UnsafeMText (toText @String txt) |] , TH.quotePat = \s -> case qqMText s of Left err -> fail $ toString err- Right txt -> [p| MTextUnsafe $(TH.litP $ TH.StringL txt) |]+ Right txt -> [p| UnsafeMText $(TH.litP $ TH.StringL txt) |] , TH.quoteType = \_ -> fail "Cannot use this QuasiQuoter at type position" , TH.quoteDec = \_ ->@@ -198,19 +198,19 @@ -- We assume that no unicode characters are used in plain Haskell code, -- so unless special tricky manipulations are used this should be safe. symbolToMText :: forall name. KnownSymbol name => MText-symbolToMText = mkMTextUnsafe $ symbolValT' @name+symbolToMText = unsafeMkMText $ symbolValT' @name -- | Create a 'MText' from label. -- -- We assume that no unicode characters are used in plain Haskell code, -- so unless special tricky manipulations are used this should be safe. labelToMText :: Label name -> MText-labelToMText = mkMTextUnsafe . labelToText+labelToMText = unsafeMkMText . labelToText -- | Leads first character of text to upper case. -- -- For empty text this will throw an error. mtextHeadToUpper :: HasCallStack => MText -> MText-mtextHeadToUpper (MTextUnsafe txt) = case T.uncons txt of+mtextHeadToUpper (UnsafeMText txt) = case T.uncons txt of Nothing -> error "Empty text"- Just (c, cs) -> MTextUnsafe $ T.cons (C.toUpper c) cs+ Just (c, cs) -> UnsafeMText $ T.cons (C.toUpper c) cs
src/Michelson/TypeCheck.hs view
@@ -11,9 +11,12 @@ , typeCheckListNoExcept , typeCheckParameter , typeCheckStorage+ , typeCheckTopLevelType , typeCheckValue+ , typeVerifyContract , typeVerifyParameter , typeVerifyStorage+ , typeVerifyTopLevelType , module E , module M , module T
src/Michelson/TypeCheck/Error.hs view
@@ -6,6 +6,7 @@ module Michelson.TypeCheck.Error ( TypeContext (..)+ , TopLevelType (..) , TCTypeError (..) , TCError (..) , ExtError (..)@@ -14,17 +15,19 @@ , pairWithElems ) where -import Fmt (Buildable(..), listF, pretty, unlinesF, (+|), (+||), (|+), (||+))+import Fmt (Buildable(..), pretty, (+|), (|+), (||+))+import Named ((:!), arg)+import Prelude hiding ((<$>), empty)+import Text.PrettyPrint.Leijen.Text hiding (pretty, bool) import qualified Text.Show (show) -import Michelson.ErrorPos (InstrCallStack(..), Pos(..), SrcPos(..))-import Michelson.Printer.Util (doesntNeedParens, printDocB, renderDoc)+import Michelson.ErrorPos (InstrCallStack(..))+import Michelson.Printer.Util (RenderDoc (..), renderAnyBuildable,+ buildRenderDoc, buildRenderDocExtended, doesntNeedParens, renderDoc, renderDocList) import Michelson.TypeCheck.TypeCheckedOp (TypeCheckedOp) import Michelson.TypeCheck.Types (SomeHST(..)) import qualified Michelson.Typed as T import Michelson.Typed.Annotation (AnnConvergeError(..))-import Michelson.Typed.Extract (toUType)-import Michelson.Typed.T (buildStack) import Michelson.Untyped (StackFn, Ty, Var) import qualified Michelson.Untyped as U import Tezos.Address (Address)@@ -43,6 +46,7 @@ | ArithmeticOperation | Iteration | Cast+ | UnpairArgument | CarArgument | CdrArgument | If@@ -50,11 +54,12 @@ | ContainerKeyType | ContainerValueType | FailwithArgument+ | TicketsJoin deriving stock (Show, Eq, Generic) deriving anyclass (NFData) -instance Buildable TypeContext where- build = \case+instance RenderDoc TypeContext where+ renderDoc _ = \case LambdaArgument -> "argument to some lambda" LambdaCode -> "code in LAMBDA" DipCode -> "code in DIP"@@ -65,6 +70,7 @@ ArithmeticOperation -> "arguments to arithmetic operation" Iteration -> "iteration (ITER / MAP / etc) code" Cast -> "argument to CAST"+ UnpairArgument -> "argument to UNPAIR" CarArgument -> "argument to CAR" CdrArgument -> "argument to CDR" If -> "conditional expression"@@ -72,7 +78,25 @@ ContainerKeyType -> "container key type" ContainerValueType -> "container value type" FailwithArgument -> "argument to FAILWITH"+ TicketsJoin -> "join of two tickets" +data TopLevelType+ = TltParameterType+ | TltStorageType+ deriving stock (Show, Eq, Generic)+ deriving anyclass (NFData)++instance Buildable TopLevelType where+ build = buildRenderDoc++instance RenderDoc TopLevelType where+ renderDoc _ = \case+ TltParameterType -> "parameter"+ TltStorageType -> "storage"++instance Buildable TypeContext where+ build = buildRenderDoc+ -- | Data type that represents various errors -- which are related to type system. -- These errors are used to specify info about type check errors@@ -96,6 +120,9 @@ -- ^ Error that happens when actual types are different from the type that instruction expects. -- The param is an non-empty list of all expected stack types that the instruction would accept. -- Each expected stack types is represented as non-empty list as well.+ | UnexpectedTopLevelType TopLevelType ("expected" :! T.T) ("got" :! T.T)+ -- ^ Error that happens when the caller expected one top-level type, but+ -- the contract has another type specified. | InvalidInstruction U.ExpandedInstr Text -- ^ Some instruction is invalid or used in an invalid way. -- For example, @PAIR 0@ or @PAIR 1@, or a @SELF@ instruction was used in a @LAMBDA@.@@ -137,49 +164,59 @@ deriving anyclass (NFData) instance Buildable TCTypeError where- build = \case- AnnError e -> build e+ build = buildRenderDocExtended++instance RenderDoc TCTypeError where+ renderDoc context = \case+ AnnError e -> renderAnyBuildable e TypeEqError type1 type2 ->- "Types not equal: " +| type1 |+ " /= " +| type2 |+ ""+ "Types not equal:" <+> (renderDoc context type1) <+> "/=" <+> (renderDoc context type2) StackEqError st1 st2 ->- "Stacks not equal: " +| buildStack st1 |+ " /= " +| buildStack st2 |+ ""+ "Stacks not equal:"<+> (renderDocList context st1) <+> "/=" <+> (renderDocList context st2) UnsupportedTypeForScope typ reason ->- "Type '" +| typ |+ "' is unsupported here because it "- +| reason |+ ""+ "Type '" <> (renderDoc context typ) <> "' is unsupported here because it"+ <+> (renderDoc context reason) NotNumericTypes t1 t2 ->- "Some of the types in an arithmetic operation are not numeric: "- +| t1 |+ " and " +| t2 |+ ""+ "Some of the types in an arithmetic operation are not numeric:"+ <+> (renderDoc context t1) <+> "and" <+> (renderDoc context t2) UnexpectedType (t :| ts) ->- "Wrong stack type for instruction, expect stack type to begin with " +|- ( intercalate " or "- $ fmap (\(x :| xs) -> "" +| listF (x:xs) |+ "")+ "Wrong stack type for instruction, expect stack type to begin with " <+>+ (cat $ punctuate "or"+ $ fmap (\(x :| xs) -> list $ fmap (renderAnyBuildable) (x:xs)) $ (t:ts)- ) |+ ""- InvalidInstruction instr reason -> unlinesF- [ "Invalid instruction " +| instr |+ ""- , "Reason: " <> reason- ]+ )+ UnexpectedTopLevelType tyDesc (arg #expected -> expected) (arg #got -> got) ->+ "Unexpected" <+> renderDoc context tyDesc <+> "type:"+ <$$> renderLargeType got+ <$$> "Expected:"+ <$$> renderLargeType expected+ InvalidInstruction instr reason ->+ "Invalid instruction" <+> (renderDoc context instr)+ <$$> "Reason:" <+> textStrict reason InvalidValueType t ->- "Value type is never a valid `" +| t |+ "`"+ "Value type is never a valid" <+> enclose "`" "`" (renderDoc context t) NotEnoughItemsOnStack -> "Not enough items on stack" UnknownContract addr ->- "Contract is not registered: " +| addr |+ ""- IllegalEntrypoint err -> build err+ "Contract is not registered:" <+> (renderAnyBuildable addr)+ IllegalEntrypoint err -> renderDoc context err EntrypointNotFound ep ->- "No such entrypoint '" +| ep |+ "'"- IllegalParamDecl err -> build err+ "No such entrypoint" <+> enclose "`" "`" (renderAnyBuildable ep)+ IllegalParamDecl err -> renderDoc context err NegativeNat -> "Natural number cannot be negative" MutezOverflow -> "Exceeds maximal value for mutez"- InvalidAddress e -> build e- InvalidKeyHash e -> build e- InvalidBls12381Object e -> build e+ InvalidAddress e -> renderDoc context e+ InvalidKeyHash e -> renderDoc context e+ InvalidBls12381Object e -> renderDoc context e InvalidTimestamp -> "Is not a valid RFC3339 timestamp" CodeAlwaysFails -> "Cannot use a terminate instruction (like FAILWITH) as part of another \ \instruction's body" EmptyCode -> "Code block is empty" AnyError -> "Some of the arguments have invalid types"+ where+ renderLargeType :: T.T -> Doc+ renderLargeType = indent 2 . renderDoc doesntNeedParens . T.toUType -- | Type check error data TCError@@ -194,42 +231,50 @@ instance NFData TCError instance Buildable TCError where- build = \case- TCFailedOnInstr instr (SomeHST t) ics mbTCTypeContext mbTCTypeError ->- "Error checking expression "- +| instr |+ " against input stack type "- +| t |+ maybe "" (\c -> ". Error in " +| c |+ "") mbTCTypeContext- +| maybe ". " (\e -> ": " +| e |+ ". ") mbTCTypeError- +| buildCallStack ics+ build = buildRenderDocExtended++instance RenderDoc TCError where+ renderDoc context = \case+ TCFailedOnInstr instr (SomeHST t) ics mbTCTypeContext mbTCTypeError -> line+ <> "Error checking expression:"+ <> surroundWithNewLines (renderDoc context instr)+ <> "against input stack type:"+ <> surroundWithNewLines (renderDoc context t)+ <> maybe "" (\c -> "Error in" <+> renderDoc context c) mbTCTypeContext+ <> maybe "" (\e -> ":" <+> (renderDoc context e) <> "." <$$> line) mbTCTypeError+ <> (renderDoc context ics) TCFailedOnValue v t custom ics mbTCTypeError ->- "Error checking value "- +| v |+ " against type "- +| toUType t |+ bool (": " +| custom |+ " ") "." (null custom)- +| (maybe "" (\e -> "\n" +| e |+ ".\n") mbTCTypeError)- +| buildCallStack ics+ "Error checking value"+ <$$> (renderDoc context v) <+> "against type"+ <+> (renderDoc context t) <> (bool (":" <+> (renderAnyBuildable custom)) "." (null custom))+ <+> (maybe "" (\e -> line <> (renderDoc context e) <> line) mbTCTypeError)+ <+> (renderDoc context ics) TCContractError msg typeError ->- "Error occurred during contract typecheck: "- +|| msg ||+ (maybe "" (\e -> " " +| e |+ "") typeError)+ "Error occurred during contract typecheck:"+ <$$> (renderAnyBuildable msg) <> (maybe "" (\e -> " " <> (renderDoc context e)) typeError) TCUnreachableCode ics instrs ->- "Unreachable code: " +| buildTruncated 3 (toList instrs) |+ ". "- +| buildCallStack ics+ "Unreachable code:" <$$> buildTruncated 3 (toList instrs) <> "."+ <+> (renderDoc context ics) TCExtError (SomeHST t) ics e ->- "Error occurred during Morley extension typecheck: "- +| e |+ " on stack " +| t |+ ". "- +| buildCallStack ics+ "Error occurred during Morley extension typecheck:" <>+ (renderAnyBuildable e) <+> "on stack" <+> (renderDoc context t) <> "."+ <+> (renderDoc context ics) TCIncompletelyTyped err contract ->- "\n"- +| printDocB False (renderDoc doesntNeedParens contract) |+ "\n"- +| build err+ line+ <> renderDoc doesntNeedParens contract+ <$> renderDoc context err where buildTruncated k l- | null (drop k l) = build l- | otherwise = build (take k l) <> " ..."- buildCallStack InstrCallStack{icsCallStack, icsSrcPos = SrcPos (Pos line) (Pos col)} =- "Error occurred on line " +| line + 1 |+ " char " +| col + 1 |+ ""- +| case icsCallStack of- [] -> "."- _ -> " inside these let defenitions: " +| listF icsCallStack |+ "."+ | null (drop k l) = renderDocList context l+ | otherwise = (renderDocList context (take k l)) <> " ..."++ -- | Helper to format a line using empty lines at the end and at the beginning,+ -- and 4-space indents for the line itself+ surroundWithNewLines :: Doc -> Doc+ surroundWithNewLines l =+ line+ <$$> indent 4 l+ <$$> line instance Show TCError where show = pretty
src/Michelson/TypeCheck/Ext.hs view
@@ -11,6 +11,7 @@ import Control.Monad.Except (MonadError, liftEither, throwError) import Data.Constraint (Dict(..)) import Data.Map.Lazy (insert, lookup)+import Data.Singletons (SingI) import Data.Typeable ((:~:)(..)) import Michelson.ErrorPos@@ -25,7 +26,7 @@ (ExpandedOp, StackFn, TyVar(..), Ty, Var, VarAnn, sfnInPattern, sfnOutPattern, sfnQuantifiedVars, varSet) import qualified Michelson.Untyped as U-import Util.Peano (SingNat(SS, SZ))+import Util.PeanoNatural (PeanoNatural(..)) -- | Perform some, possibly throwing, action presumably making use of a supplied -- external instruction. In case of an error, return @IllTypedSeq@ wrapping the@@ -40,7 +41,7 @@ (pure . WellTypedSeq) typeCheckExt- :: forall s. Typeable s+ :: forall s. SingI s => TcInstrHandler -> U.ExpandedExtInstr -> HST s@@ -49,8 +50,8 @@ instrPos <- ask case ext of U.STACKTYPE s -> workOnInstr ext $- liftExtError hst $ nopSomeInstr <$ checkStackType noBoundVars s hst- U.FN t sf op -> checkFn tcInstr t sf op hst+ liftExtError hst $ stackTypeSomeInstr s <$ checkStackType noBoundVars s hst+ U.FN t sf op -> checkFn tcInstr t sf op hst instrPos U.UPRINT pc -> workOnInstr ext $ verifyPrint pc <&> \tpc -> toSomeInstr (T.PRINT tpc) U.UTEST_ASSERT U.TestAssert{..} -> do@@ -81,9 +82,9 @@ T.PrintComment <$> traverse checkStRef pc toSomeInstr ext' = hst :/ T.Ext ext' ::: hst- nopSomeInstr = hst :/ T.Nop ::: hst+ stackTypeSomeInstr s = hst :/ T.Ext (T.STACKTYPE s) ::: hst -liftExtError :: Typeable s => HST s -> Either ExtError a -> TypeCheckInstr a+liftExtError :: SingI s => HST s -> Either ExtError a -> TypeCheckInstr a liftExtError hst ei = do instrPos <- ask liftEither $ first (TCExtError (SomeHST hst) instrPos) ei@@ -98,18 +99,19 @@ -- | Executes function body, pushing @ExtFrame@ onto the state and checks -- the pattern in @FN@. checkFn- :: Typeable inp+ :: SingI inp => TcInstrHandler -> Text -> StackFn -> [ExpandedOp] -> HST inp+ -> InstrCallStack -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)-checkFn tcInstr t sf body inp = do+checkFn tcInstr t sf body inp loc = do guarding (con body) (checkStart inp) $ \vars -> preserving (typeCheckImplStripped tcInstr body inp) con $ \someI@(_ :/ instrAndOut) -> case instrAndOut of- _ ::: out -> checkEnd vars out $> someI+ _ ::: out -> checkEnd vars out $> mapSomeInstr (T.WithLoc loc . T.Fn t sf) someI AnyOutInstr{} -> pure someI where checkStart hst = do@@ -118,7 +120,7 @@ tcExtFramesL %= (vars :) return vars - checkEnd :: Typeable out => BoundVars -> HST out -> TypeCheckInstr ()+ checkEnd :: SingI out => BoundVars -> HST out -> TypeCheckInstr () checkEnd vars out = liftExtError out $ void $ checkStackType vars (sfnOutPattern sf) out @@ -127,14 +129,14 @@ -- | Check that a @StackTypePattern@ matches the type of the current stack checkStackType- :: Typeable xs+ :: SingI xs => BoundVars -> U.StackTypePattern -> HST xs -> Either ExtError BoundVars checkStackType (BoundVars vars boundStkRest) s hst = go vars 0 s hst where- go :: Typeable xs => Map Var Ty -> Int -> U.StackTypePattern -> HST xs+ go :: SingI xs => Map Var Ty -> Int -> U.StackTypePattern -> HST xs -> Either ExtError BoundVars go m _ U.StkRest sr = case boundStkRest of Nothing -> pure $ BoundVars m (Just $ SomeHST sr)@@ -165,7 +167,7 @@ -- -- Fails when index is too large for the given stack. createStackRef- :: (MonadError TCError m, MonadReader InstrCallStack m, Typeable s)+ :: (MonadError TCError m, MonadReader InstrCallStack m, SingI s) => Natural -> HST s -> m (T.StackRef s) createStackRef idx hst = case doCreate (hst, idx) of@@ -179,7 +181,7 @@ doCreate :: forall s. (HST s, Natural) -> Maybe (T.StackRef s) doCreate = \case (SNil, _) -> Nothing- ((_ ::& _), 0) -> Just (T.StackRef SZ)+ ((_ ::& _), 0) -> Just (T.StackRef Zero) ((_ ::& st), i) -> do T.StackRef ns <- doCreate (st, i - 1)- return $ T.StackRef (SS ns)+ return $ T.StackRef (Succ ns)
src/Michelson/TypeCheck/Helpers.hs view
@@ -51,8 +51,8 @@ import Data.Constraint (Dict(..), withDict) import Data.Default (def) import Data.Singletons (Sing, SingI(sing), demote)+import Data.Singletons.Decide import qualified Data.Text as T-import Data.Typeable (eqT, (:~:)(..)) import Data.Vinyl (Rec(..)) import Fmt ((+||), (||+)) @@ -63,15 +63,16 @@ import Michelson.TypeCheck.Types import Michelson.Typed (BadTypeForScope(..), CommentType(StackTypeComment), Comparable, ExtInstr(COMMENT_ITEM),- Instr(..), KnownT, Notes(..), SingT(..), T(..), WellTyped, converge, getComparableProofS, notesT,- starNotes)+ Instr(..), Notes(..), SingT(..), T(..), WellTyped, converge, getComparableProofS, notesT,+ requireEq, starNotes) import Michelson.Typed.Annotation (AnnConvergeError, isStar) import Michelson.Typed.Arith (Add, ArithOp(..), Mul, Sub, UnaryArithOp(..)) import Michelson.Typed.Polymorphic (ConcatOp, EDivOp(..), GetOp(..), MemOp(..), SizeOp, SliceOp, UpdOp(..))- import qualified Michelson.Untyped as Un-import Michelson.Untyped.Annotation (Annotation(..), FieldAnn, VarAnn, orAnn, annQ, mkAnnotationUnsafe, noAnn)+import Michelson.Untyped.Annotation+ (Annotation(..), FieldAnn, VarAnn, annQ, noAnn, orAnn, unsafeMkAnnotation)+import Util.Sing (eqI) import Util.Type (onFirst) -- | Function which derives special annotations@@ -100,7 +101,7 @@ splitLastDot v = case unsnoc $ T.splitOn "." $ unAnnotation v of Nothing -> def Just (_, "") -> (def, Un.convAnn v)- Just (vs, l) -> (foldMap mkAnnotationUnsafe vs, bool (mkAnnotationUnsafe l) def (l == "car" || l == "cdr"))+ Just (vs, l) -> (foldMap unsafeMkAnnotation vs, bool (unsafeMkAnnotation l) def (l == "car" || l == "cdr")) commonPrefix :: VarAnn -> VarAnn -> VarAnn commonPrefix = curry \case@@ -114,6 +115,9 @@ deriveSpecialVN :: VarAnn -> FieldAnn -> VarAnn -> VarAnn -> VarAnn deriveSpecialVN vn elFn pairVN elVn | (unAnnotation vn) == "%" = Un.convAnn elFn+ -- TODO [#534]:+ -- In the `%%` branch, if the pair's field annotation (`elFn`) is empty, we should default it to "cdr"/"car".+ -- See: <https://tezos.gitlab.io/008/michelson.html#automatic-variable-and-field-annotations-inferring> | (unAnnotation vn) == "%%" = pairVN <> Un.convAnn elFn | otherwise = vn `orAnn` elVn @@ -163,11 +167,10 @@ -- | Check whether the given stack types are equal. eqHST- :: forall as bs.- (Typeable as, Typeable bs)+ :: forall as bs. (SingI as, SingI bs) => HST as -> HST bs -> Either TCTypeError (as :~: bs) eqHST (hst :: HST xs) (hst' :: HST ys) = do- case eqT @as @bs of+ case eqI @as @bs of Nothing -> Left $ StackEqError (hstToTs hst) (hstToTs hst') Just Refl -> do void $ convergeHST hst hst' `onFirst` AnnError@@ -176,12 +179,11 @@ -- | Check whether the given stack has size 1 and its only element matches the -- given type. This function is a specialized version of `eqHST`. eqHST1- :: forall t st.- (Typeable st, WellTyped t)+ :: forall t st. (SingI st, WellTyped t) => HST st -> Either TCTypeError (st :~: '[t]) eqHST1 hst = do let hst' = sing @t -:& SNil- case eqT @'[t] @st of+ case eqI @'[t] @st of Nothing -> Left $ StackEqError (hstToTs hst') (hstToTs hst) Just Refl -> Right Refl @@ -203,13 +205,13 @@ else Left $ "Entries are unordered (" +|| e1 ||+ " >= " +|| e2 ||+ ")" l -> Right l --- | Function @eqType@ is a simple wrapper around @Data.Typeable.eqT@ suited+-- | Function @eqType@ is a simple wrapper around @Data.Singletons.decideEquality@ suited -- for use within @Either TCTypeError a@ applicative. eqType- :: forall (a :: T) (b :: T).- (Each '[KnownT] [a, b])+ :: forall (a :: T) (b :: T). (Each '[SingI] [a, b]) => Either TCTypeError (a :~: b)-eqType = maybe (Left $ TypeEqError (demote @a) (demote @b)) pure eqT+eqType =+ requireEq @a @b $ Left ... TypeEqError onTypeCheckInstrErr :: (MonadReader InstrCallStack m, MonadError TCError m)@@ -247,14 +249,14 @@ throwError $ TCFailedOnInstr instr hst pos mContext (Just err) onTypeCheckInstrAnnErr- :: (MonadReader InstrCallStack m, MonadError TCError m, Typeable ts)+ :: (MonadReader InstrCallStack m, MonadError TCError m, SingI ts) => Un.ExpandedInstr -> HST ts -> Maybe TypeContext -> Either AnnConvergeError a -> m a onTypeCheckInstrAnnErr instr i mContext ei = onTypeCheckInstrErr instr (SomeHST i) mContext (ei `onFirst` AnnError) withCompareableCheck- :: forall a m v ts. (Typeable ts, MonadReader InstrCallStack m, MonadError TCError m)+ :: forall a m v ts. (SingI ts, MonadReader InstrCallStack m, MonadError TCError m) => Sing a -> Un.ExpandedInstr -> HST ts@@ -265,7 +267,7 @@ Nothing -> typeCheckInstrErr instr (SomeHST i) $ Just ComparisonArguments typeCheckOpImpl- :: forall inp. Typeable inp+ :: forall inp. SingI inp => TcInstrHandler -> Un.ExpandedOp -> HST inp@@ -293,11 +295,11 @@ <&> mapSeq (addNotes . mapSomeInstr Nested) addNotes :: SomeInstr inp -> SomeInstr inp- addNotes (inp :/ i ::: out) = inp :/ wrapWithNotes inp out i ::: out+ addNotes (inp :/ i ::: out) = inp :/ wrapWithNotes out i ::: out addNotes i = i - wrapWithNotes :: HST c -> HST d -> Instr c d -> Instr c d- wrapWithNotes inputStack outputStack instr = case instr of+ wrapWithNotes :: HST d -> Instr c d -> Instr c d+ wrapWithNotes outputStack instr = case instr of -- Abstractions for instructions: Nop -> instr' Seq _ _ -> instr'@@ -306,6 +308,7 @@ Ext _ -> instr' FrameInstr _ _ -> instr' WithLoc _ _ -> instr'+ Fn {} -> instr' -- These three shouldn't happen, since annotations are added here. InstrWithNotes {} -> instr' InstrWithVarAnns _ _ -> instr'@@ -329,6 +332,24 @@ FAILWITH -> instr' NEVER -> instr' + -- These instructions technically may have one/two explicit var anns, BUT because they support special var anns,+ -- the var anns are stored directly inside the instruction's constructor.+ -- For this reason, they must NOT be wrapped in `InstrWithVarNotes`.+ AnnCAR _ _ -> instr'+ AnnCDR _ _ -> instr'+ AnnUNPAIR{} ->+ case outputStack of+ (notes1, _, varAnn1) ::& (notes2, _, varAnn2) ::& _ ->+ let withNotes+ | isStar notes1 && isStar notes2 = id+ | isStar notes2 = InstrWithNotes Proxy (notes1 :& RNil)+ | otherwise = InstrWithNotes Proxy (notes1 :& notes2 :& RNil)+ withVarAnns+ | varAnn1 == def && varAnn2 == def = id+ | varAnn2 == def = InstrWithVarAnns $ Un.OneVarAnn varAnn1+ | otherwise = InstrWithVarAnns (Un.TwoVarAnns varAnn1 varAnn2)+ in withNotes $ withVarAnns instr+ -- We purposefully don't wrap `UNPAIRN` in meta-instructions -- like `InstrWithNotes` and `InstrWithVarAnns`. -- See !769 for a lengthy explanation.@@ -354,20 +375,6 @@ withVarNotes' = if valVarAnn == Un.noAnn && mapVarAnn == Un.noAnn then id else InstrWithVarAnns $ Un.TwoVarAnns valVarAnn mapVarAnn in withNotes . withVarNotes . withVarNotes' $ instr - -- Instructions that produce at most one note:- -- The cases for Ann{CAR,CDR} basically try to answer the question:- -- were the var annotations explicitly written or do they come from- -- unnesting nested annotations?- AnnCAR _ -> case (inputStack, outputStack) of- ((NTPair _ _ _ vn1 _vn2 _ _, _, _) ::& _, (_, _, vn) ::& _)- | vn /= def && vn /= vn1 -> instr''- | vn1 == def -> instr''- | otherwise -> instr'- AnnCDR _ -> case (inputStack, outputStack) of- ((NTPair _ _ _ _vn1 vn2 _ _, _, _) ::& _, (_, _, vn) ::& _)- | vn /= def && vn /= vn2 -> instr''- | vn2 == def -> instr''- | otherwise -> instr' DUP -> instr'' DUPN _ -> instr'' PUSH _ -> instr''@@ -445,6 +452,10 @@ SHA3 -> instr'' KECCAK -> instr'' PAIRING_CHECK -> instr''+ TICKET -> instr''+ READ_TICKET -> instr''+ SPLIT_TICKET -> instr''+ JOIN_TICKETS -> instr'' where instr' = addNotesNoVarAnn outputStack instr instr'' = addNotesOneVarAnn outputStack instr@@ -469,7 +480,7 @@ -- | Like 'typeCheckImpl' but doesn't add a stack type comment after the -- sequence. typeCheckImplNoLastTypeComment- :: forall inp . Typeable inp+ :: forall inp . SingI inp => TcInstrHandler -> [Un.ExpandedOp] -> HST inp@@ -522,7 +533,7 @@ -- | 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+ :: forall inp . SingI inp => TcInstrHandler -> [Un.ExpandedOp] -> HST inp@@ -534,7 +545,7 @@ continueTypeChecking tcInstr done ops typeCheckImpl- :: forall inp . Typeable inp+ :: forall inp . SingI inp => TcInstrHandler -> [Un.ExpandedOp] -> HST inp@@ -605,7 +616,7 @@ -- | Check whether given types are structurally equal and annotations converge. matchTypes :: forall t1 t2.- (Each '[KnownT] [t1, t2])+ (Each '[SingI] [t1, t2]) => Notes t1 -> Notes t2 -> Either TCTypeError (t1 :~: t2, Notes t1) matchTypes n1 n2 = do Refl <- eqType @t1 @t2@@ -620,8 +631,9 @@ memImpl :: forall c memKey rs inp m . ( MemOp c- , KnownT (MemOpKey c)+ , SingI (MemOpKey c) , inp ~ (memKey : c : rs)+ , SingI rs , MonadReader InstrCallStack m , MonadError TCError m )@@ -630,7 +642,7 @@ -> VarAnn -> m (SomeInstr inp) memImpl cKeyNotes inputHST@(hst0 ::& _ ::& hstTail) varAnn =- case eqType @memKey @(MemOpKey c) of+ case eqType @memKey @(MemOpKey c) of Right Refl -> do _ <- onTypeCheckInstrAnnErr uInstr inputHST (Just ContainerKeyType) (converge memKeyNotes cKeyNotes)@@ -644,9 +656,10 @@ getImpl :: forall c getKey rs inp m .- ( GetOp c, KnownT (GetOpKey c)+ ( GetOp c, SingI (GetOpKey c) , WellTyped (GetOpVal c) , inp ~ (getKey : c : rs)+ , SingI rs , MonadReader InstrCallStack m , MonadError TCError m )@@ -671,7 +684,8 @@ updImpl :: forall c updKey updParams rs inp m . ( UpdOp c- , KnownT (UpdOpKey c), KnownT (UpdOpParams c)+ , SingI (UpdOpKey c), SingI (UpdOpParams c)+ , SingI rs , inp ~ (updKey : updParams : c : rs) , MonadReader InstrCallStack m , MonadError TCError m@@ -703,9 +717,10 @@ getUpdImpl :: forall c updKey updParams rs inp m . ( UpdOp c, GetOp c- , KnownT (UpdOpKey c)- , KnownT (GetOpVal c)+ , SingI (UpdOpKey c)+ , SingI (GetOpVal c) , inp ~ (updKey : updParams : c : rs)+ , SingI rs , GetOpKey c ~ UpdOpKey c , UpdOpParams c ~ 'TOption (GetOpVal c) , MonadReader InstrCallStack m@@ -744,7 +759,7 @@ pure $ i :/ SIZE ::: ((starNotes, Dict, vn) ::& rs) sliceImpl- :: (SliceOp c, Typeable c, inp ~ ('TNat ': 'TNat ': c ': rs), Monad m)+ :: (SliceOp c, inp ~ ('TNat ': 'TNat ': c ': rs), Monad m) => HST inp -> Un.VarAnn -> m (SomeInstr inp)@@ -779,7 +794,6 @@ arithImpl :: forall aop inp m n s t. ( ArithOp aop n m- , Typeable (ArithRes aop n m ': s) , WellTyped (ArithRes aop n m) , inp ~ (n ': m ': s) , MonadReader InstrCallStack t@@ -799,9 +813,9 @@ addImpl :: forall a b inp rs m.- ( Typeable rs- , Each '[KnownT] [a, b]+ ( Each '[SingI] [a, b] , inp ~ (a ': b ': rs)+ , SingI rs , MonadReader InstrCallStack m , MonadError TCError m )@@ -826,8 +840,8 @@ edivImpl :: forall a b inp rs m.- ( Typeable rs- , Each '[KnownT] [a, b]+ ( SingI rs+ , Each '[SingI] [a, b] , inp ~ (a ': b ': rs) , MonadReader InstrCallStack m , MonadError TCError m@@ -868,9 +882,9 @@ subImpl :: forall a b inp rs m.- ( Typeable rs- , Each '[KnownT] [a, b]+ ( Each '[SingI] [a, b] , inp ~ (a ': b ': rs)+ , SingI rs , MonadReader InstrCallStack m , MonadError TCError m )@@ -892,9 +906,9 @@ mulImpl :: forall a b inp rs m.- ( Typeable rs- , Each '[KnownT] [a, b]+ ( Each '[SingI] [a, b] , inp ~ (a ': b ': rs)+ , SingI rs , MonadReader InstrCallStack m , MonadError TCError m )@@ -923,8 +937,7 @@ -- | Helper function to construct instructions for unary arithmetic -- operations. unaryArithImpl- :: ( Typeable (UnaryArithRes aop n ': s)- , WellTyped (UnaryArithRes aop n)+ :: ( WellTyped (UnaryArithRes aop n) , inp ~ (n ': s) , Monad t )@@ -938,8 +951,7 @@ -- | Helper function to construct instructions for unary arithmetic -- operations that should preserve annotations. unaryArithImplAnnotated- :: ( Typeable (UnaryArithRes aop n ': s)- , WellTyped (UnaryArithRes aop n)+ :: ( WellTyped (UnaryArithRes aop n) , inp ~ (n ': s) , Monad t , n ~ UnaryArithRes aop n
src/Michelson/TypeCheck/Instr.hs view
@@ -36,9 +36,12 @@ , typeCheckListNoExcept , typeCheckParameter , typeCheckStorage+ , typeCheckTopLevelType , typeCheckValue+ , typeVerifyContract , typeVerifyParameter , typeVerifyStorage+ , typeVerifyTopLevelType ) where import Prelude hiding (EQ, GT, LT)@@ -46,8 +49,10 @@ import Control.Monad.Except (MonadError, catchError, liftEither, throwError) import Data.Default (def) import Data.Generics (everything, mkQ)-import Data.Singletons (Sing, demote)+import Data.Singletons (Sing, demote, withSingI, withSomeSing) import Data.Typeable ((:~:)(..))+import Fmt (pretty)+import Named ((!)) import Michelson.ErrorPos import Michelson.TypeCheck.Error@@ -63,38 +68,59 @@ import Michelson.Typed hiding (Branch(..)) import Util.Peano+import Util.PeanoNatural+import Util.Sing (SingI1(..)) import Util.Type (onFirst, type (++)) import qualified Michelson.Untyped as U-import Michelson.Untyped.Annotation (FieldTag, VarAnn, VarTag, convAnn, orAnn, annQ)+import Michelson.Untyped.Annotation (FieldTag, VarAnn, VarTag, annQ, convAnn, orAnn) -- | Type check a contract and verify that the given storage -- is of the type expected by the contract.-typeCheckContractAndStorage :: U.Contract -> U.Value -> Either TCError SomeContractAndStorage+typeCheckContractAndStorage+ :: U.Contract -> U.Value -> TypeCheckResult SomeContractAndStorage typeCheckContractAndStorage uContract uStorage = do- SomeContract (contract@Contract{} :: Contract cp st) <- typeCheckContract uContract def+ SomeContract (contract@Contract{} :: Contract cp st) <- typeCheckContract uContract storage <- typeVerifyStorage @st uStorage- Right $ SomeContractAndStorage contract storage+ pure $ SomeContractAndStorage contract storage typeCheckContract :: U.Contract- -> TypeCheckOptions- -> Either TCError SomeContract-typeCheckContract c options = do- paramType <- mkSomeParamType (U.contractParameter c)- runTypeCheck (TypeCheckContract paramType) options $ typeCheckContractImpl c+ -> TypeCheckResult SomeContract+typeCheckContract c = do+ paramType <- liftEither $ mkSomeParamType (U.contractParameter c)+ runTypeCheck (TypeCheckContract paramType) $ typeCheckContractImpl c +typeVerifyContract+ :: forall cp st.+ (SingI cp, SingI st)+ => U.Contract -> TypeCheckResult (Contract cp st)+typeVerifyContract uContract = do+ SomeContract tContract@(Contract{} :: Contract cp' st') <-+ typeCheckContract uContract+ Refl <- requireEq @cp' @cp (mkErr TltParameterType)+ Refl <- requireEq @st' @st (mkErr TltParameterType)+ return tContract+ where+ mkErr :: TopLevelType -> T -> T -> TypeCheckResult any+ mkErr tyDesc got expected =+ throwError $ TCContractError "error in contract type" $ Just $+ UnexpectedTopLevelType tyDesc+ ! #expected expected+ ! #got got+ withWTP :: forall t a. SingI t => (WellTyped t => TypeCheck a) -> TypeCheck a withWTP fn = case getWTP @t of Right Dict -> fn- Left (NotWellTyped t) -> throwError $ TCContractError ("Not a well typed value: " <> show t) Nothing+ Left (NotWellTyped t cause) -> throwError $ TCContractError+ ("Not a well typed value: '" <> show t <> "' because it " <> pretty cause) Nothing withWTPInstr_ :: forall t a. SingI t => U.ExpandedInstr -> SomeHST -> (WellTyped t => TypeCheckInstr a) -> TypeCheckInstr a withWTPInstr_ v t fn = case getWTP @t of Right Dict -> fn- Left (NotWellTyped badType) -> do+ Left (NotWellTyped badType cause) -> do loc <- ask- throwError $ TCFailedOnInstr v t loc Nothing (Just $ UnsupportedTypeForScope badType BtNotComparable)+ throwError $ TCFailedOnInstr v t loc Nothing (Just $ UnsupportedTypeForScope badType cause) withWTPInstr'_ :: forall t inp. SingI t@@ -104,10 +130,10 @@ -> TypeCheckInstrNoExcept (TypeCheckedSeq inp) withWTPInstr'_ v t fn = case getWTP @t of Right Dict -> fn- Left (NotWellTyped badType) -> do+ Left (NotWellTyped badType cause) -> do loc <- ask let err = TCFailedOnInstr v t loc Nothing- (Just $ UnsupportedTypeForScope badType BtNotComparable)+ (Just $ UnsupportedTypeForScope badType cause) pure $ IllTypedSeq err [NonTypedInstr $ U.PrimEx v] typeCheckContractImpl@@ -202,7 +228,7 @@ -- -- As a second argument, @typeCheckList@ accepts input stack type representation. typeCheckList- :: (Typeable inp)+ :: (SingI inp) => [U.ExpandedOp] -> HST inp -> TypeCheck (SomeInstr inp)@@ -215,7 +241,7 @@ -- 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)+ :: (SingI inp) => [U.ExpandedOp] -> HST inp -> TypeCheckNoExcept (TypeCheckedSeq inp) typeCheckListNoExcept = usingReaderT def ... typeCheckImpl typeCheckInstr @@ -239,19 +265,19 @@ typeVerifyParameter :: SingI t- => TcOriginatedContracts -> U.Value -> Either TCError (Value t)+ => TcOriginatedContracts -> U.Value -> TypeCheckResult (Value t) typeVerifyParameter originatedContracts = typeVerifyTopLevelType (Just originatedContracts) typeVerifyStorage :: SingI t- => U.Value -> Either TCError (Value t)+ => U.Value -> TypeCheckResult (Value t) typeVerifyStorage = typeVerifyTopLevelType Nothing typeVerifyTopLevelType :: forall t. SingI t- => Maybe TcOriginatedContracts -> U.Value -> Either TCError (Value t)+ => Maybe TcOriginatedContracts -> U.Value -> TypeCheckResult (Value t) typeVerifyTopLevelType mOriginatedContracts valueU =- runTypeCheck (TypeCheckValue (valueU, demote @t)) def $ usingReaderT def $+ runTypeCheck (TypeCheckValue (valueU, demote @t)) $ usingReaderT def $ typeCheckValImpl mOriginatedContracts typeCheckInstr valueU -- | Like 'typeCheckValue', but for values to be used as parameter.@@ -259,47 +285,47 @@ -- Also accepts a 'TcOriginatedContracts' in order to be able to type-check -- @contract p@ values (which can only be part of a parameter). typeCheckParameter- :: TcOriginatedContracts -> U.Ty -> U.Value -> Either TCError SomeValue+ :: TcOriginatedContracts -> U.Ty -> U.Value -> TypeCheckResult SomeValue typeCheckParameter originatedContracts = typeCheckTopLevelType (Just originatedContracts) -- | Like 'typeCheckValue', but for values to be used as storage. typeCheckStorage- :: U.Ty -> U.Value -> Either TCError SomeValue+ :: U.Ty -> U.Value -> TypeCheckResult SomeValue typeCheckStorage = typeCheckTopLevelType Nothing typeCheckTopLevelType- :: Maybe TcOriginatedContracts -> U.Ty -> U.Value -> Either TCError SomeValue+ :: Maybe TcOriginatedContracts -> U.Ty -> U.Value -> TypeCheckResult SomeValue typeCheckTopLevelType mOriginatedContracts typeU valueU =- withSomeSingT (fromUType typeU) $ \(_ :: Sing t) ->- SomeValue <$> typeVerifyTopLevelType @t mOriginatedContracts valueU+ withSomeSing (fromUType typeU) $ \(s :: Sing t) ->+ withSingI s $ SomeValue <$> typeVerifyTopLevelType @t mOriginatedContracts valueU -- | Helper data type we use to typecheck DUPN. data TCDupNHelper inp where TCDupNHelper :: forall (n :: Peano) inp out a.- (Typeable out, ConstraintDUPN n inp out a) =>- Sing n -> HST out -> TCDupNHelper inp+ (SingI out, ConstraintDUPN n inp out a, DupableScope a) =>+ PeanoNatural n -> HST out -> TCDupNHelper inp -- | Helper data type we use to typecheck DROPN. data TCDropHelper inp where TCDropHelper :: forall (n :: Peano) inp out.- (Typeable out, SingI n, KnownPeano n, LongerOrSameLength inp n, Drop n inp ~ out) =>- Sing n -> HST out -> TCDropHelper inp+ (SingI out, LongerOrSameLength inp n, Drop n inp ~ out) =>+ PeanoNatural n -> HST out -> TCDropHelper inp -- | Helper data type we use to typecheck DIG. data TCDigHelper inp where TCDigHelper :: forall (n :: Peano) inp out a.- (Typeable out, ConstraintDIG n inp out a) =>- Sing n -> HST out -> TCDigHelper inp+ (SingI out, ConstraintDIG n inp out a) =>+ PeanoNatural n -> HST out -> TCDigHelper inp -- | Helper data type we use to typecheck DUG. data TCDugHelper inp where TCDugHelper :: forall (n :: Peano) inp out a.- (Typeable out, ConstraintDUG n inp out a) =>- Sing n -> HST out -> TCDugHelper inp+ (SingI out, ConstraintDUG n inp out a) =>+ PeanoNatural n -> HST out -> TCDugHelper inp -- | Helper data type we use to typecheck PAIRN. --@@ -308,8 +334,8 @@ data TCPairNHelper inp where TCPairNHelper :: forall (n :: Peano) (inp :: [T]).- (Typeable (PairN n inp), ConstraintPairN n inp) =>- Sing n -> HST (PairN n inp) -> TCPairNHelper inp+ (SingI (PairN n inp), ConstraintPairN n inp) =>+ PeanoNatural n -> HST (PairN n inp) -> TCPairNHelper inp -- | Helper data type we use to typecheck UNPAIRN. --@@ -318,8 +344,8 @@ data TCUnpairNHelper (inp :: [T]) where TCUnpairNHelper :: forall (n :: Peano) (a :: T) (b :: T) (rest :: [T]).- (Typeable (UnpairN n ('TPair a b) ++ rest), ConstraintUnpairN n ('TPair a b)) =>- Sing n -> HST (UnpairN n ('TPair a b) ++ rest) -> TCUnpairNHelper ('TPair a b : rest)+ (SingI (UnpairN n ('TPair a b) ++ rest), ConstraintUnpairN n ('TPair a b)) =>+ PeanoNatural n -> HST (UnpairN n ('TPair a b) ++ rest) -> TCUnpairNHelper ('TPair a b : rest) -- | Helper data type we use to typecheck GETN. --@@ -328,8 +354,8 @@ data TCGetNHelper (inp :: [T]) where TCGetNHelper :: forall (ix :: Peano) (pair :: T) (rest :: [T]).- (Typeable (GetN ix pair ': rest), ConstraintGetN ix pair) =>- Sing ix -> HST (GetN ix pair ': rest) -> TCGetNHelper (pair : rest)+ (SingI (GetN ix pair ': rest), ConstraintGetN ix pair) =>+ PeanoNatural ix -> HST (GetN ix pair ': rest) -> TCGetNHelper (pair : rest) -- | Helper data type we use to typecheck UPDATEN. --@@ -338,8 +364,8 @@ data TCUpdateNHelper (inp :: [T]) where TCUpdateNHelper :: forall (ix :: Peano) (val :: T) (pair :: T) (rest :: [T]).- (Typeable (UpdateN ix val pair ': rest), ConstraintUpdateN ix pair) =>- Sing ix -> HST (UpdateN ix val pair ': rest) -> TCUpdateNHelper (val : pair : rest)+ (SingI (UpdateN ix val pair ': rest), ConstraintUpdateN ix pair) =>+ PeanoNatural ix -> HST (UpdateN ix val pair ': rest) -> TCUpdateNHelper (val : pair : rest) -- | Helper function to convert a simple throwing typechecking action into a -- non-throwing one, embedding possible errors into the type checking tree.@@ -353,7 +379,7 @@ -- | Less verbose version of `lift ... typeCheckListNoExcept`. tcList- :: (Typeable inp)+ :: (SingI inp) => [U.ExpandedOp] -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp) tcList ops stack = lift $ typeCheckListNoExcept ops stack @@ -383,19 +409,22 @@ go nTotal inputHST <&> \case TCDropHelper s out -> inputHST :/ DROPN s ::: out where- go :: forall inp. Typeable inp+ go :: forall inp. SingI inp => Word -> HST inp -> TypeCheckInstr (TCDropHelper inp) go = curry \case- (0, i) -> pure (TCDropHelper SZ i)+ (0, i) -> pure (TCDropHelper Zero i) (_, SNil) -> notEnoughItemsOnStack' (n, (_ ::& iTail)) -> do- go (n - 1) iTail <&> \(TCDropHelper s out) -> TCDropHelper (SS s) out+ go (n - 1) iTail <&> \(TCDropHelper s out) -> TCDropHelper (Succ s) out - (U.DUP vn1, a@(n, d, _vn2) ::& rs) -> workOnInstr uInstr $+ (U.DUP vn1, a@(n :: Notes t, d, _vn2) ::& rs) -> workOnInstr uInstr $ do+ Dict <-+ onScopeCheckInstrErr @t uInstr (SomeHST inp) Nothing $+ checkScope @(DupableScope t) pure (inp :/ DUP ::: ((n, d, vn1) ::& a ::& rs)) (U.DUP _vn, SNil) -> notEnoughItemsOnStack@@ -403,7 +432,7 @@ (U.DUPN vn nTotal, inputHST) -> workOnInstr uInstr $ go nTotal inputHST <&> \(TCDupNHelper s out) -> inputHST :/ DUPN s ::: out where- go :: forall inp. Typeable inp+ go :: forall inp. SingI inp => Word -> HST inp -> TypeCheckInstr (TCDupNHelper inp)@@ -415,11 +444,15 @@ -- Don't bind whatever variable annotation is here because DUP n doesn't -- duplicate variable annotations. This is consistent with tezos-client.- (1, i@((an, dict, _) ::& _)) -> pure (TCDupNHelper (SS SZ) ((an, dict, vn) ::& i))+ (1, i@((an :: Notes a, dict, _) ::& _)) -> do+ Dict <-+ onScopeCheckInstrErr @a uInstr (SomeHST inp) Nothing $+ checkScope @(DupableScope a)+ pure (TCDupNHelper One ((an, dict, vn) ::& i)) (n, (b ::& iTail)) ->- go (n - 1) iTail <&> \(TCDupNHelper s@(SS _) (a ::& resTail)) ->- TCDupNHelper (SS s) (a ::& b ::& resTail)+ go (n - 1) iTail <&> \(TCDupNHelper s@(Succ _) (a ::& resTail)) ->+ TCDupNHelper (Succ s) (a ::& b ::& resTail) (U.SWAP, a ::& b ::& rs) -> workOnInstr uInstr $ pure (inp :/ SWAP ::: (b ::& a ::& rs))@@ -429,7 +462,7 @@ (U.DIG nTotal, inputHST) -> workOnInstr uInstr $ go nTotal inputHST <&> \(TCDigHelper s out) -> inputHST :/ DIG s ::: out where- go :: forall inp. Typeable inp+ go :: forall inp. SingI inp => Word -> HST inp -> TypeCheckInstr (TCDigHelper inp)@@ -437,25 +470,25 @@ -- Even 'DIG 0' is invalid on empty stack (so it is not strictly `Nop`). (_, SNil) -> notEnoughItemsOnStack' - (0, i@(_ ::& _)) -> pure (TCDigHelper SZ i)+ (0, i@(_ ::& _)) -> pure (TCDigHelper Zero i) (n, (b ::& iTail)) -> go (n - 1) iTail <&> \(TCDigHelper s (a ::& resTail)) ->- TCDigHelper (SS s) (a ::& b ::& resTail)+ TCDigHelper (Succ s) (a ::& b ::& resTail) (U.DUG nTotal, inputHST) -> workOnInstr uInstr $ go nTotal inputHST <&> \(TCDugHelper s out) -> inputHST :/ DUG s ::: out where- go :: forall inp. Typeable inp+ go :: forall inp. SingI inp => Word -> HST inp -> TypeCheckInstr (TCDugHelper inp) go = curry \case- (0, i@(_ ::& _)) -> pure (TCDugHelper SZ i)+ (0, i@(_ ::& _)) -> pure (TCDugHelper Zero i) (n, (a ::& b ::& iTail)) -> go (n - 1) (a ::& iTail) <&> \(TCDugHelper s resTail) ->- TCDugHelper (SS s) (b ::& resTail)+ TCDugHelper (Succ s) (b ::& resTail) -- Two cases: -- 1. Input stack is empty.@@ -499,7 +532,27 @@ pure (inp :/ AnnPAIR tn pfn qfn ::: ((NTPair tn pfn' qfn' avn bvn an bn, Dict, vn') ::& rs)) (U.PAIR {}, _) -> notEnoughItemsOnStack+ (U.UNPAIR instrVn1 instrVn2 instrFn1 instrFn2, (NTPair _ fn1 fn2 vn1 vn2 n1 n2, Dict, vn) ::& rs) ->+ workOnInstr uInstr $ do+ -- We purposefully ignore the result of `convergeDestrAnns` here.+ -- We're only interested in checking that the instruction's field ann matches the pair's field ann,+ -- we don't need to "unify" them.+ _ <- onTypeCheckInstrAnnErr uInstr inp (Just UnpairArgument) (convergeDestrAnns fn1 instrFn1)+ _ <- onTypeCheckInstrAnnErr uInstr inp (Just UnpairArgument) (convergeDestrAnns fn2 instrFn2) + let vn1' = deriveSpecialVN instrVn1 fn1 vn vn1+ let vn2' = deriveSpecialVN instrVn2 fn2 vn vn2+ pure $+ inp :/ AnnUNPAIR instrVn1 instrVn2 instrFn1 instrFn2 :::+ ( (n1, Dict, vn1') ::&+ (n2, Dict, vn2') ::&+ rs+ )++ (U.UNPAIR {}, _ ::& _) ->+ failWithErr $ UnexpectedType $ ("pair 'a 'b" :| []) :| []++ (U.UNPAIR {}, _) -> notEnoughItemsOnStack (U.PAIRN varAnn nTotal, _) -> workOnInstr uInstr $ do go nTotal inp <&> \case TCPairNHelper s out -> inp :/ PAIRN s ::: addVarAnn out@@ -511,32 +564,26 @@ (InvalidInstruction uInstr "'PAIR n' expects n ≥ 2") | n == 2 = case hst of- (an :: Notes a, _, avn) ::& (bn :: Notes b, _, bvn) ::& hstTail -> do+ (an :: Notes a, _, _) ::& (bn :: Notes b, _, _) ::& hstTail -> do withWTPInstr @('TPair a b) $ do- pure $ TCPairNHelper (SS (SS SZ)) $- (mkNotes an bn avn bvn, Dict, U.noAnn) ::& hstTail+ pure $ TCPairNHelper Two $+ (mkNotes an bn, Dict, U.noAnn) ::& hstTail _ -> notEnoughItemsOnStack' | otherwise = case hst of- (an :: Notes a, _, avn) ::& hstTail@(_ ::& _ ::& _) -> do+ (an :: Notes a, _, _) ::& hstTail@(_ ::& _ ::& _) -> do go (n - 1) hstTail >>= \case- TCPairNHelper nSing@(SS (SS _)) ((bn :: Notes b, _, bvn) ::& hstTail') -> do+ TCPairNHelper nSing@(Succ (Succ _)) ((bn :: Notes b, _, _) ::& hstTail') -> do withWTPInstr @('TPair a b) $ do- pure $ TCPairNHelper (SS nSing) $- (mkNotes an bn avn bvn, Dict, U.noAnn) ::& hstTail'+ pure $ TCPairNHelper (Succ nSing) $+ (mkNotes an bn, Dict, U.noAnn) ::& hstTail' _ -> notEnoughItemsOnStack' - -- | @PAIR n@ instructions take the variable annotations of each- -- element in the stack and turn them into field annotations. E.g.:- --- -- > /* [ @bb nat : @aa nat ] */ ;- -- > PAIR 2- -- > /* [ pair (nat %bb) (nat %aa) ] */ ;- mkNotes :: forall a b. Notes a -> Notes b -> VarAnn -> VarAnn -> Notes ('TPair a b)- mkNotes an bn avn bvn =+ mkNotes :: forall a b. Notes a -> Notes b -> Notes ('TPair a b)+ mkNotes an bn = NTPair U.noAnn- (convAnn @VarTag @FieldTag avn) (convAnn @VarTag @FieldTag bvn) U.noAnn U.noAnn+ U.noAnn U.noAnn an bn -- | If a @PAIR n@ instruction has a variable annotation,@@ -563,7 +610,7 @@ | n == 2 = case hst of (NTPair _ aFieldAnn bFieldAnn _ _ aNotes bNotes, Dict, _) ::& rest -> do- pure $ TCUnpairNHelper (SS (SS SZ)) $+ pure $ TCUnpairNHelper Two $ (aNotes, Dict, convAnn @FieldTag @VarTag aFieldAnn) ::& (bNotes, Dict, convAnn @FieldTag @VarTag bFieldAnn) ::& rest@@ -572,35 +619,34 @@ case hst of (NTPair _ aFieldAnn _ _ _ aNotes bNotes, Dict, _) ::& rest -> do go (n - 1) ((bNotes, Dict, U.noAnn) ::& rest) >>= \case- TCUnpairNHelper nSing@(SS (SS _)) out -> do- pure $ TCUnpairNHelper (SS nSing) $+ TCUnpairNHelper nSing@(Succ (Succ _)) out -> do+ pure $ TCUnpairNHelper (Succ nSing) $ (aNotes, Dict, convAnn @FieldTag @VarTag aFieldAnn) ::& out _ -> unexpectedType unexpectedType :: TypeCheckInstr a unexpectedType = failWithErr' $ UnexpectedType $ (pairWithElems nTotal :| []) :| [] - (U.CAR vn fn, (STPair{}, NTPair pairTN pfn qfn pvn qvn (pns :: Notes p) (qns :: Notes q), _, pairVN) ::&+ rs) -> workOnInstr uInstr $ do- pfn' <- onTypeCheckInstrAnnErr uInstr inp (Just CarArgument) (convergeDestrAnns fn pfn)- withWTPInstr @p $- withWTPInstr @('TPair p q) $ do- let vn' = deriveSpecialVN vn pfn' pairVN pvn- i' = (NTPair pairTN pfn' qfn pvn qvn pns qns, Dict, pairVN) ::& rs- pure $ i' :/ AnnCAR fn ::: ((pns, Dict, vn') ::& rs)+ (U.CAR vn fn, (STPair{}, NTPair _ pfn _ pvn _ pns _, Dict, pairVN) ::&+ rs) -> workOnInstr uInstr $ do+ -- We purposefully ignore the result of `convergeDestrAnns` here.+ -- We're only interested in checking that the instruction's field ann matches the pair's field ann,+ -- we don't need to "unify" them.+ _ <- onTypeCheckInstrAnnErr uInstr inp (Just CarArgument) (convergeDestrAnns fn pfn)+ let vn' = deriveSpecialVN vn pfn pairVN pvn+ pure $ inp :/ AnnCAR vn fn ::: ((pns, Dict, vn') ::& rs) (U.CAR _ _, _ ::& _) -> failWithErr $ UnexpectedType $ ("pair 'a 'b" :| []) :| [] (U.CAR _ _, SNil) -> notEnoughItemsOnStack - (U.CDR vn fn, (STPair{}, NTPair pairTN pfn qfn pvn qvn (pns :: Notes p) (qns :: Notes q), _, pairVN) ::&+ rs) -> workOnInstr uInstr $ do- qfn' <- onTypeCheckInstrAnnErr uInstr inp (Just CdrArgument) (convergeDestrAnns fn qfn)-- withWTPInstr @q $- withWTPInstr @('TPair p q) $ do- let vn' = deriveSpecialVN vn qfn' pairVN qvn- i' = (NTPair pairTN pfn qfn' pvn qvn pns qns, Dict, pairVN) ::& rs- pure $ i' :/ AnnCDR fn ::: ((qns, Dict, vn') ::& rs)+ (U.CDR vn fn, (STPair{}, NTPair _ _ qfn _ qvn _ qns, Dict, pairVN) ::&+ rs) -> workOnInstr uInstr $ do+ -- We purposefully ignore the result of `convergeDestrAnns` here.+ -- We're only interested in checking that the instruction's field ann matches the pair's field ann,+ -- we don't need to "unify" them.+ _ <- onTypeCheckInstrAnnErr uInstr inp (Just CdrArgument) (convergeDestrAnns fn qfn)+ let vn' = deriveSpecialVN vn qfn pairVN qvn+ pure $ inp :/ AnnCDR vn fn ::: ((qns, Dict, vn') ::& rs) (U.CDR _ _, _ ::& _) -> failWithErr $ UnexpectedType $ ("pair 'a 'b" :| []) :| []@@ -625,9 +671,9 @@ (U.RIGHT {}, SNil) -> notEnoughItemsOnStack - (U.IF_LEFT mp mq, (STOr{}, ons, _, ovn) ::&+ rs) -> do+ (U.IF_LEFT mp mq, (STOr lt rt, ons, _, ovn) ::&+ rs) -> do case deriveNsOr ons ovn of- (an :: Notes a, bn :: Notes b, avn, bvn) ->+ (an :: Notes a, bn :: Notes b, avn, bvn) -> withSingI lt $ withSingI rt $ withWTPInstr' @a $ withWTPInstr' @b $ do let@@ -700,12 +746,12 @@ 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+ (U.MAP vn mp, (STList l, NTList _ (vns :: Notes t1), Dict, _vn) ::&+ _) -> withSingI l $ do 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+ (U.MAP vn mp, (STMap k v, NTMap _ kns vns, Dict, _vn) ::&+ _) -> withSingI k $ withSingI v $ do case NTPair def def def def def kns vns of (pns :: Notes ('TPair k v1)) -> withWTPInstr' @('TPair k v1) $@@ -720,15 +766,15 @@ (U.MAP _ _, SNil) -> notEnoughItemsOnStack - (U.ITER is, (STSet (_ :: Sing t1), NTSet _ en, _, _) ::&+ _) -> do+ (U.ITER is, (STSet (s :: Sing t1), NTSet _ en, _, _) ::&+ _) -> withSingI s $ do withWTPInstr' @t1 $ iterImpl en uInstr is inp - (U.ITER is, (STList (_ :: Sing t1), NTList _ en, _, _) ::&+ _) -> do+ (U.ITER is, (STList (l :: Sing t1), NTList _ en, _, _) ::&+ _) -> withSingI l $ do withWTPInstr' @t1 $ iterImpl en uInstr is inp - (U.ITER is, (STMap _ _, NTMap _ kns vns, _, _) ::&+ _) -> do+ (U.ITER is, (STMap k v, NTMap _ kns vns, _, _) ::&+ _) -> withSingI k $ withSingI v $ do case NTPair def def def def def kns vns of (en :: Notes ('TPair a b)) -> withWTPInstr' @('TPair a b) $ iterImpl en uInstr is inp@@ -743,13 +789,15 @@ (U.ITER _, SNil) -> notEnoughItemsOnStack (U.MEM varNotes,- _ ::& (STSet{}, NTSet _ notesK, _, _) ::&+ _) -> workOnInstr uInstr $+ _ ::& (STSet s, NTSet _ notesK, _, _) ::&+ _) -> withSingI s $ workOnInstr uInstr $ memImpl notesK inp varNotes (U.MEM varNotes,- _ ::& (STMap{}, NTMap _ notesK _, _, _) ::&+ _) -> workOnInstr uInstr $+ _ ::& (STMap k v, NTMap _ notesK _, _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ memImpl notesK inp varNotes (U.MEM varNotes,- _ ::& (STBigMap{}, NTBigMap _ notesK _, _, _) ::&+ _) -> workOnInstr uInstr $+ _ ::& (STBigMap k v, NTBigMap _ notesK _, _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ memImpl notesK inp varNotes (U.MEM _, _ ::& _ ::& _) -> failWithErr $ UnexpectedType@@ -761,12 +809,12 @@ (U.MEM _, _) -> notEnoughItemsOnStack (U.GET varNotes,- _ ::& (STMap{}, NTMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->- workOnInstr uInstr $ withWTPInstr @v $+ _ ::& (STMap k v, NTMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ withWTPInstr @v $ getImpl notesK inp notesV varNotes (U.GET varNotes,- _ ::& (STBigMap{}, NTBigMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->- workOnInstr uInstr $ withWTPInstr @v $+ _ ::& (STBigMap k v, NTBigMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ withWTPInstr @v $ getImpl notesK inp notesV varNotes (U.GET _, _ ::& _ ::& _) ->@@ -785,23 +833,23 @@ where go :: forall x xs. Word -> HST (x : xs) -> TypeCheckInstr (TCGetNHelper (x : xs)) go 0 ((a, Dict, _) ::& rest) =- pure $ TCGetNHelper SZ ((a, Dict, getNVarAnn) ::& rest)+ pure $ TCGetNHelper Zero ((a, Dict, getNVarAnn) ::& rest) go 1 ((NTPair _ _ _ _ _ leftNotes _, Dict, _) ::& rest) =- pure $ TCGetNHelper (SS SZ) $ (leftNotes, Dict, getNVarAnn) ::& rest+ pure $ TCGetNHelper One $ (leftNotes, Dict, getNVarAnn) ::& rest go ix ((NTPair _ _ _ _ _ _ rightNotes, Dict, _) ::& rest) = go (ix - 2) ((rightNotes, Dict, U.noAnn) ::& rest) <&> \(TCGetNHelper ixSing out) ->- TCGetNHelper (SS (SS ixSing)) out+ TCGetNHelper (Succ (Succ ixSing)) out go _ _ = failWithErr' $ UnexpectedType $ (pairWithNodeIndex ix0 :| []) :| [] (U.UPDATE varAnn,- _ ::& _ ::& (STMap{}, (NTMap _ notesK (notesV :: Notes v)), _, _) ::&+ _) ->- workOnInstr uInstr $ updImpl notesK inp (NTOption U.noAnn notesV) varAnn+ _ ::& _ ::& (STMap k v, (NTMap _ notesK (notesV :: Notes v)), _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ updImpl notesK inp (NTOption U.noAnn notesV) varAnn (U.UPDATE varAnn,- _ ::& _ ::& (STBigMap{}, NTBigMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->- workOnInstr uInstr $ updImpl notesK inp (NTOption U.noAnn notesV) varAnn+ _ ::& _ ::& (STBigMap k v, NTBigMap _ notesK (notesV :: Notes v), _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ updImpl notesK inp (NTOption U.noAnn notesV) varAnn (U.UPDATE varAnn,- _ ::& _ ::& (STSet{}, NTSet _ (notesK :: Notes k), _, _) ::&+ _) ->- workOnInstr uInstr $ updImpl notesK inp (NTBool U.noAnn) varAnn+ _ ::& _ ::& (STSet s, NTSet _ (notesK :: Notes k), _, _) ::&+ _) ->+ withSingI s $ workOnInstr uInstr $ updImpl notesK inp (NTBool U.noAnn) varAnn (U.UPDATE _, _ ::& _ ::& _ ::& _) -> failWithErr $ UnexpectedType@@ -819,27 +867,27 @@ where go :: forall val pair rest. Word -> HST (val : pair : rest) -> TypeCheckInstr (TCUpdateNHelper (val : pair : rest)) go 0 ((valNotes, Dict, _) ::& (_, _, _) ::& rest) =- pure $ TCUpdateNHelper SZ $+ pure $ TCUpdateNHelper Zero $ (valNotes, Dict, updateNVarAnn) ::& rest go 1 ((valNotes, Dict, _) ::& (NTPair pairTA leftFA rightFA leftVA rightVA _ rightNotes, Dict, _) ::& rest) =- pure $ TCUpdateNHelper (SS SZ) $+ pure $ TCUpdateNHelper One $ (NTPair pairTA leftFA rightFA leftVA rightVA valNotes rightNotes, Dict, updateNVarAnn) ::& rest go ix (val ::& (NTPair pairTA leftFA rightFA leftVA rightVA leftNotes rightNotes, Dict, _) ::& rest) = go (ix - 2) (val ::& (rightNotes, Dict, U.noAnn) ::& rest) <&> \(TCUpdateNHelper ixSing ((updatedRightNotes, Dict, _) ::& outRest)) ->- TCUpdateNHelper (SS (SS ixSing)) $+ TCUpdateNHelper (Succ (Succ ixSing)) $ (NTPair pairTA leftFA rightFA leftVA rightVA leftNotes updatedRightNotes, Dict, updateNVarAnn) ::& outRest go _ _ = failWithErr' $ UnexpectedType $ ("'val" :| [pairWithNodeIndex ix0]) :| [] (U.UPDATEN _ _, _) -> notEnoughItemsOnStack (U.GET_AND_UPDATE varAnn,- _ ::& _ ::& (STMap{}, (NTMap _ notesK (notesV :: Notes v)), _, _) ::&+ _) ->- workOnInstr uInstr $+ _ ::& _ ::& (STMap k v, (NTMap _ notesK (notesV :: Notes v)), _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ withWTPInstr @v $ getUpdImpl notesK inp (NTOption U.noAnn notesV) varAnn (U.GET_AND_UPDATE varAnn,- _ ::& _ ::& (STBigMap{}, (NTBigMap _ notesK (notesV :: Notes v)), _, _) ::&+ _) ->- workOnInstr uInstr $+ _ ::& _ ::& (STBigMap k v, (NTBigMap _ notesK (notesV :: Notes v)), _, _) ::&+ _) ->+ withSingI k $ withSingI v $ workOnInstr uInstr $ withWTPInstr @v $ getUpdImpl notesK inp (NTOption U.noAnn notesV) varAnn (U.GET_AND_UPDATE _, _ ::& _ ::& _ ::& _) ->@@ -907,12 +955,12 @@ lamImpl (U.LAMBDA vn p1 p2) uInstr is vn ins ons i (U.EXEC vn, ((tn :: Notes t1), _, _)- ::& ( STLambda _ _+ ::& ( STLambda v b , NTLambda _ (t1n :: Notes t1') (t2n :: Notes t2') , _ , _ )- ::&+ rs) -> workOnInstr uInstr $ do+ ::&+ rs) -> withSingI v $ withSingI b $ workOnInstr uInstr $ do Refl <- onTypeCheckInstrErr uInstr (SomeHST inp) (Just LambdaArgument) (eqType @t1 @t1') (Refl, _) <- errM $ matchTypes tn t1n@@ -928,11 +976,11 @@ (U.EXEC _, _) -> notEnoughItemsOnStack (U.APPLY vn, ((_ :: Notes a'), _, _)- ::& ( STLambda (STPair _ _) _+ ::& ( STLambda (STPair lt rt) b , NTLambda vann (NTPair _ _ _ _ _ (_ :: Notes a) (nb :: Notes b)) sc , _ , _)- ::&+ rs) -> workOnInstr uInstr $ do+ ::&+ rs) -> withSingI lt $ withSingI rt $ withSingI b $ workOnInstr uInstr $ do case NTLambda vann nb sc of (l2n :: Notes ('TLambda t1 t2)) -> withWTPInstr @('TLambda t1 t2) $ do @@ -962,21 +1010,21 @@ TCDipHelperErr err rest -> IllTypedSeq err rest TCDipHelperOk s subI out -> WellTypedSeq $ inputHST :/ DIPN s subI ::: out where- go :: forall inp. Typeable inp+ go :: forall inp. SingI inp => Word -> HST inp -> TypeCheckInstrNoExcept (TCDipHelper inp) go n curHST = case (n, curHST) of (0, _) -> typeCheckDipBody (U.DIPN nTotal) uInstr instructions curHST (TCDipHelperErr)- (TCDipHelperOk SZ)+ (TCDipHelperOk Zero) (_, 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- TCDipHelperOk s subI out -> TCDipHelperOk (SS s) subI (hstHead ::& out)+ TCDipHelperOk s subI out -> TCDipHelperOk (Succ s) subI (hstHead ::& out) TCDipHelperErr err rest -> TCDipHelperErr err rest (u, v) -> case (u, v) of -- Workaround for not exceeding -fmax-pmcheck-iterations limit@@ -1286,7 +1334,7 @@ (U.TRANSFER_TOKENS vn, ((_ :: Notes p'), _, _) ::& (NTMutez{}, _, _)- ::& (STContract (_ :: Sing p), _, _, _) ::&+ rs) -> workOnInstr uInstr $ do+ ::& (STContract (s :: Sing p), _, _, _) ::&+ rs) -> withSingI s $ workOnInstr uInstr $ do proofScope <- onScopeCheckInstrErr @p uInstr (SomeHST inp) (Just ContractParameter) $ checkScope @(ParameterScope p) case (eqType @p @p', proofScope) of@@ -1434,6 +1482,40 @@ (U.NEVER, (NTNever{}, _, _) ::& _) -> workOnInstr uInstr $ pure $ inp :/ AnyOutInstr NEVER + (U.TICKET vn, (stVal :: Sing v, _, _, _) ::&+ (NTNat{}, _, _) ::& rs) -> workOnInstr uInstr $+ withWTPInstr @v $+ withCompareableCheck stVal uInstr inp $+ inp :/ TICKET ::: ((starNotes, Dict, vn) ::& rs)+ (U.TICKET _, _ ::& _ ::& _) ->+ failWithErr $ UnexpectedType $ ("a'" :| ["nat"]) :| []+ (U.TICKET _, _) -> notEnoughItemsOnStack++ (U.READ_TICKET vn, ticket@(ntTicket@NTTicket{}, Dict, _) ::& rs) -> workOnInstr uInstr $+ case notesSing ntTicket of+ STTicket{} ->+ pure $ inp :/ READ_TICKET ::: ((starNotes, Dict, vn) ::& ticket ::& rs)+ (U.READ_TICKET _, _ ::& _) ->+ failWithErr $ UnexpectedType $ ("ticket 'a" :| []) :| []+ (U.READ_TICKET _, _) -> notEnoughItemsOnStack++ (U.SPLIT_TICKET vn, (NTTicket{}, Dict, _) ::& (NTPair _ _ _ _ _ NTNat{} NTNat{}, _, _) ::& rs) ->+ workOnInstr uInstr $+ pure $ inp :/ SPLIT_TICKET ::: ((starNotes, Dict, vn) ::& rs)+ (U.SPLIT_TICKET _, _ ::& _ ::& _) ->+ failWithErr $ UnexpectedType $ ("pair nat nat" :| ["ticket 'a"]) :| []+ (U.SPLIT_TICKET _, _) -> notEnoughItemsOnStack++ (U.JOIN_TICKETS vn,+ (STPair{}, NTPair _ _ _ _ _ nt1@NTTicket{} nt2@NTTicket{}, Dict, _) ::&+ rs) ->+ workOnInstr uInstr $ do+ (Refl, nt) <-+ onTypeCheckInstrErr uInstr (SomeHST inp) (Just TicketsJoin) $+ matchTypes nt1 nt2+ pure $ inp :/ JOIN_TICKETS ::: ((NTOption U.noAnn nt, Dict, vn) ::& rs)+ (U.JOIN_TICKETS _, _ ::& _) ->+ failWithErr $ UnexpectedType $ ("pair (ticket 'a) (ticket 'a)" :| []) :| []+ (U.JOIN_TICKETS _, _) -> notEnoughItemsOnStack+ -- Could not get rid of the catch all clause due to this warning: -- @ -- Pattern match checker exceeded (2000000) iterations in@@ -1469,7 +1551,7 @@ -- value. genericIf :: forall bti bfi cond rs .- (Typeable bti, Typeable bfi)+ (SingI bti, SingI bfi) => (forall s'. Instr bti s' -> Instr bfi s' ->@@ -1502,17 +1584,17 @@ pure $ AnyOutInstr (cons p q) mapImpl- :: forall c rs .+ :: forall c rs. ( MapOp c , WellTyped (MapOpInp c)- , Typeable (MapOpRes c)+ , SingI1 (MapOpRes c) ) => ([TypeCheckedOp] -> TypeCheckedInstr) -> Notes (MapOpInp c) -> U.ExpandedInstr -> [U.ExpandedOp] -> HST (c ': rs)- -> (forall v' . (KnownT v') =>+ -> (forall v'. (SingI v') => Notes v' -> HST rs -> TypeCheckInstr (HST (MapOpRes c v' ': rs))) -> TypeCheckInstrNoExcept (TypeCheckedSeq (c ': rs)) mapImpl cons vn instr mp i@(_ ::& rs) mkRes = do@@ -1520,11 +1602,11 @@ case subp of sub ::: subo -> case subo of- (bn, _, _bvn) ::& rs' -> do+ (bn :: Notes v', _, _bvn) ::& rs' -> do Refl <- onTypeCheckInstrErr instr (SomeHST i) (Just Iteration) $ eqHST rs rs' x <- mkRes bn rs'- pure $ i :/ MAP sub ::: x+ pure $ i :/ withSingI1 @(MapOpRes c) @v' (MAP sub ::: x) _ -> typeCheckInstrErr instr (SomeHST i) (Just Iteration) AnyOutInstr _ -> typeCheckInstrErr' instr (SomeHST i) (Just Iteration) CodeAlwaysFails@@ -1555,7 +1637,7 @@ lamImpl :: forall it ot ts . ( WellTyped it, WellTyped ot- , Typeable ts+ , SingI ts ) => ([TypeCheckedOp] -> TypeCheckedInstr) -> U.ExpandedInstr@@ -1601,18 +1683,18 @@ data TCDipHelper inp where 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+ (SingI out, ConstraintDIPN n inp out s s') =>+ PeanoNatural n -> Instr s s' -> HST out -> TCDipHelper inp TCDipHelperErr :: TCError -> [IllTypedInstr] -> TCDipHelper inp typeCheckDipBody- :: Typeable inp+ :: SingI inp => ([TypeCheckedOp] -> TypeCheckedInstr) -> U.ExpandedInstr -> [U.ExpandedOp] -> HST inp -> (TCError -> [IllTypedInstr] -> r)- -> (forall out. Typeable out => Instr inp out -> HST out -> r)+ -> (forall out. SingI out => Instr inp out -> HST out -> r) -> TypeCheckInstrNoExcept r typeCheckDipBody cons mainInstr instructions inputHST onErr onOk = do listRes <- lift $ typeCheckListNoExcept instructions inputHST
src/Michelson/TypeCheck/TypeCheck.hs view
@@ -5,16 +5,17 @@ module Michelson.TypeCheck.TypeCheck ( TcInstrHandler , TcOriginatedContracts- , TcResult , TypeCheckEnv(..) , TypeCheckOptions(..) , TypeCheck , TypeCheckNoExcept+ , TypeCheckResult , runTypeCheck , TypeCheckInstr , TypeCheckInstrNoExcept , runTypeCheckIsolated , runTypeCheckInstrIsolated+ , typeCheckingWith , liftNoExcept , liftNoExcept' , throwingTCError@@ -30,11 +31,12 @@ , TypeCheckMode(..) , SomeParamType(..) , mkSomeParamType- , mkSomeParamTypeUnsafe+ , unsafeMkSomeParamType ) where -import Control.Monad.Except (throwError)+import Control.Monad.Except (Except, mapExceptT, runExcept, throwError)+import Control.Monad.Reader (mapReaderT) import Data.Default (Default(..)) import Data.Singletons (Sing) import Fmt (Buildable, build, pretty)@@ -47,6 +49,7 @@ tcsEither) import Michelson.TypeCheck.Types import qualified Michelson.Typed as T+import Michelson.Typed (SingI) import qualified Michelson.Untyped as U import Tezos.Address (ContractHash) import Util.Lens@@ -62,6 +65,15 @@ (ReaderT TypeCheckOptions (State TypeCheckEnv)) +-- | Monad for performing some typechecking operations with the same options.+--+-- Unlike 'TypeCheck' monad, this does not carry the context of intra-contract+-- or intra-value typechecking.+-- TODO [this MR]: probably come up with a better name? IntraTypeCheck?+type TypeCheckResult =+ (ReaderT TypeCheckOptions+ (Except TCError))+ data SomeParamType = forall t. (T.ParameterScope t) => SomeParamType (Sing t) (T.ParamNotes t) @@ -80,14 +92,14 @@ -- | Helper function means to provide a quick way for creating instance -- of @SomeParamType@ needed in test. someParamToParameterType :: SomeParamType -> U.ParameterType-someParamToParameterType (SomeParamType s T.ParamNotesUnsafe{..}) =+someParamToParameterType (SomeParamType s T.UnsafeParamNotes{..}) = U.ParameterType (T.AsUTypeExt s pnNotes) pnRootAnn -- | Construct @SomeParamType@ from @ParameterType@, mainly used in test.-mkSomeParamTypeUnsafe :: HasCallStack => U.ParameterType -> SomeParamType-mkSomeParamTypeUnsafe p =+unsafeMkSomeParamType :: HasCallStack => U.ParameterType -> SomeParamType+unsafeMkSomeParamType p = case mkSomeParamType p of- Right sp -> sp+ Right sp -> sp Left err -> error $ "Illegal type in parameter of env contract: " <> pretty err mkSomeParamType :: U.ParameterType -> Either TCError SomeParamType@@ -118,19 +130,31 @@ } data TypeCheckOptions = TypeCheckOptions- { tcVerbose :: Bool -- ^ Whether to add stack type comments after every- -- instruction a la tezos-client.+ { tcVerbose :: Bool+ -- ^ Whether to add stack type comments after every+ -- instruction a la tezos-client.+ , tcStrict :: Bool+ -- ^ Whether should we behave like in test run or real run+ -- (real run is more strict).+ --+ -- @tezos-client run@'s behaviour can slightly differ from the behaviour+ -- of @tezos-client originate@ and @tezos-client transfer@. For instance,+ -- some values can be "forged" in test run, but not in a real one,+ -- see: Note [Tickets forging].+ --+ -- Set this to @True@ when need to match the behaviour in the network,+ -- and to @False@ if you prefer providing the user with some convenient+ -- features. } instance Default TypeCheckOptions where- def = TypeCheckOptions{ tcVerbose = False }+ def = TypeCheckOptions{ tcVerbose = False, tcStrict = True } makeLensesWith postfixLFields ''TypeCheckEnv -runTypeCheck :: TypeCheckMode -> TypeCheckOptions -> TypeCheck a -> Either TCError a-runTypeCheck mode options = evaluatingState (TypeCheckEnv [] mode)- . runExceptT- . usingReaderT options+runTypeCheck :: TypeCheckMode -> TypeCheck a -> TypeCheckResult a+runTypeCheck mode =+ mapReaderT $ mapExceptT $ evaluatingStateT (TypeCheckEnv [] mode) -- | Run type checker as if it worked isolated from other world - -- no access to environment of the current contract is allowed.@@ -140,10 +164,11 @@ -- whatever we typecheck does not depend on the parameter type of the -- contract which is being typechecked (because there is no contract -- that we are typechecking).-runTypeCheckIsolated :: TypeCheck a -> Either TCError a-runTypeCheckIsolated = runTypeCheck TypeCheckTest def+runTypeCheckIsolated :: TypeCheck a -> TypeCheckResult a+runTypeCheckIsolated = runTypeCheck TypeCheckTest -type TcResult inp = Either TCError (SomeInstr inp)+typeCheckingWith :: TypeCheckOptions -> TypeCheckResult a -> Either TCError a+typeCheckingWith options = runExcept . usingReaderT options type TypeCheckInstr = ReaderT InstrCallStack TypeCheck@@ -152,7 +177,7 @@ ReaderT InstrCallStack TypeCheckNoExcept -- | Similar to 'runTypeCheckIsolated', but for 'TypeCheckInstr.'-runTypeCheckInstrIsolated :: TypeCheckInstr a -> Either TCError a+runTypeCheckInstrIsolated :: TypeCheckInstr a -> TypeCheckResult a runTypeCheckInstrIsolated = runTypeCheckIsolated . flip runReaderT def liftNoExcept :: TypeCheckInstrNoExcept a -> TypeCheckInstr a@@ -249,7 +274,7 @@ -- have to be refactored too. -- Therefore, I am using ReaderT over TypeCheck. type TcInstrHandler- = forall inp. (Typeable inp, HasCallStack)+ = forall inp. (SingI inp, HasCallStack) => U.ExpandedInstr -> HST inp -> TypeCheckInstrNoExcept (TypeCheckedSeq inp)
src/Michelson/TypeCheck/TypeCheckedOp.hs view
@@ -11,12 +11,12 @@ , someInstrToOp ) where -import Data.Typeable (cast)+import Data.Singletons (SingI) 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.Typed.Instr (Instr, castInstr) import Michelson.Untyped.Instr (ExpandedOp, InstrAbstract(..)) import Util.TH (deriveGADTNFData) @@ -26,13 +26,13 @@ -- | Represents nodes of a partially typed operation tree. data TypeCheckedOp where -- | Constructs well-typed node.- WellTypedOp :: (Typeable inp, Typeable out) => Instr inp out -> TypeCheckedOp+ WellTypedOp :: (SingI inp, SingI 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+ WellTypedOp i1 == WellTypedOp i2 = castInstr i1 == Just i2 IllTypedOp i1 == IllTypedOp i2 = i1 == i2 _ == _ = False @@ -55,7 +55,7 @@ SNil -> go rest (::&){} -> go rest where- go :: forall inp. Typeable inp => SomeInstrOut inp -> TypeCheckedOp+ go :: forall inp. SingI inp => SomeInstrOut inp -> TypeCheckedOp go (i ::: _) = WellTypedOp i go (AnyOutInstr i) = WellTypedOp (i @'[])
src/Michelson/TypeCheck/Types.hs view
@@ -9,12 +9,11 @@ , SomeHST (..) , SomeInstrOut (..) , SomeInstr (..)- , SomeContract (..)- , SomeContractAndStorage (..) , BoundVars (..) , TcExtFrames , NotWellTyped (..) , getWTP+ , getWTP_ , withWTPm , unsafeWithWTP , mapSomeContract@@ -25,18 +24,21 @@ import Data.Constraint (Dict(..)) import qualified Data.Map.Lazy as Map-import Data.Singletons (Sing, SingI(..), demote)-import Fmt (Buildable(..), Builder, (+|), (|+), pretty)+import Data.Singletons (Sing, SingI(..), demote, withSingI)+import Fmt (Buildable(..), pretty) import Prelude hiding (EQ, GT, LT) import qualified Text.Show+import Text.PrettyPrint.Leijen.Text hiding (pretty) -import Michelson.Typed (ParameterScope, StorageScope, Notes(..), T(..), SingT(..), notesT, starNotes)-import Michelson.Typed.Haskell.Value (WellTyped)++import Michelson.Typed (Notes(..), SingT(..), SomeContract(..), T(..), notesT, starNotes) import qualified Michelson.Typed as T+import Michelson.Typed.Haskell.Value (WellTyped) import Michelson.Typed.Instr+import Michelson.Printer.Util import Michelson.Untyped (Ty, Var, noAnn) import Michelson.Untyped.Annotation (VarAnn)-import Util.Typeable+import Util.Sing (eqParamSing) -- | Data type holding type information for stack (Heterogeneous Stack Type). --@@ -63,7 +65,7 @@ -- Additionally constructor keeps 'SingI' constraint for the current type. data HST (ts :: [T]) where SNil :: HST '[]- (::&) :: (Typeable xs, T.KnownT x)+ (::&) :: (T.SingI x, T.SingI xs) => (Notes x, Dict (WellTyped x), VarAnn) -> HST xs -> HST (x ': xs)@@ -82,14 +84,16 @@ showDo ((notesT -> t, Dict, _vn) ::& SNil) = show t instance Buildable (HST ts) where- build SNil = "[]"- build (r ::& rs) = "[ " +| showDo (r ::& rs) |+ " ]"- where- showDo :: HST (t ': ts_) -> Builder- showDo ((notesT -> t, Dict, _vn) ::& (b ::& c)) =- build t |+ ", " +| showDo (b ::& c)- showDo ((notesT -> t, Dict, _vn) ::& SNil) = build t+ build = buildRenderDocExtended +instance RenderDoc (HST ts) where+ renderDoc _ SNil = "[]"+ renderDoc context (r ::& rs) = "[" <+> doRender (r ::& rs) <+> "]"+ where+ doRender :: HST (t ': ts_) -> Doc+ doRender ((notesT -> t, Dict, _vn) ::& (b ::& c)) =+ renderDoc context t <> "," <+> doRender (b ::& c)+ doRender ((notesT -> t, Dict, _vn) ::& SNil) = renderDoc context t infixr 7 ::& instance Eq (HST ts) where@@ -100,7 +104,7 @@ -- | Append a type to 'HST', assuming that notes and annotations -- for this type are unknown. (-:&)- :: (Typeable xs, WellTyped x)+ :: (WellTyped x, SingI xs) => Sing x -> HST xs -> HST (x ': xs)@@ -112,7 +116,7 @@ pattern (::&+) :: () => ( ys ~ (x ': xs)- , T.KnownT x, Typeable xs+ , SingI x, SingI xs ) => (Sing x, Notes x, Dict (WellTyped x), VarAnn) -> HST xs@@ -122,14 +126,14 @@ -- | No-argument type wrapper for @HST@ data type. data SomeHST where- SomeHST :: Typeable ts => HST ts -> SomeHST+ SomeHST :: SingI ts => HST ts -> SomeHST deriving stock instance Show SomeHST instance NFData SomeHST where rnf (SomeHST h) = rnf h instance Eq SomeHST where- SomeHST hst1 == SomeHST hst2 = hst1 `eqParam1` hst2+ SomeHST hst1 == SomeHST hst2 = hst1 `eqParamSing` hst2 -- | This data type keeps part of type check result - instruction and -- corresponding output stack.@@ -139,7 +143,7 @@ -- Output stack type is wrapped inside the type and @Typeable@ -- constraint is provided to allow convenient unwrapping. (:::)- :: (Typeable out)+ :: SingI out => Instr inp out -> HST out -> SomeInstrOut inp@@ -182,31 +186,12 @@ instance Show (ExtInstr inp) => Show (SomeInstr inp) where show (inp :/ out) = show inp <> " -> " <> show out -data SomeContract where- SomeContract :: Contract cp st -> SomeContract--instance NFData SomeContract where- rnf (SomeContract c) = rnf c- mapSomeContract :: (forall inp out. Instr inp out -> Instr inp out) -> SomeContract -> SomeContract mapSomeContract f (SomeContract fc) = SomeContract $ mapContractCode f fc -deriving stock instance Show SomeContract---- | Represents a typed contract & a storage value of the type expected by the contract.-data SomeContractAndStorage where- SomeContractAndStorage- :: forall cp st.- (StorageScope st, ParameterScope cp)- => Contract cp st- -> T.Value st- -> SomeContractAndStorage--deriving stock instance Show SomeContractAndStorage- -- | Set of variables defined in a let-block. data BoundVars = BoundVars (Map Var Ty) (Maybe SomeHST) @@ -217,12 +202,14 @@ type TcExtFrames = [BoundVars] -- | Error type for when a value is not well-typed.-data NotWellTyped = NotWellTyped T+data NotWellTyped = NotWellTyped+ { nwtBadType :: T+ , nwtCause :: T.BadTypeForScope+ } 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"+ build (NotWellTyped t c) =+ "Given type is not well typed because '" <> (build t) <> "' " <> (build c) fromEDict :: Either e (Dict a) -> (a => Either e (Dict b)) -> Either e (Dict b) fromEDict ma b = ma >>= (\Dict -> b)@@ -235,30 +222,62 @@ STUnit -> Right Dict STSignature -> Right Dict STChainId -> Right Dict- STOption s -> fromEDict (getWTP_ s) (Right Dict)- STList s -> fromEDict (getWTP_ s) (Right Dict)+ STOption s -> withSingI s $ fromEDict (getWTP_ s) (Right Dict)+ STList s -> withSingI s $ fromEDict (getWTP_ s) (Right Dict) STSet (s :: Sing si) ->+ withSingI s $ fromEDict (getWTP_ s) $ fromEDict- ( maybeToRight (NotWellTyped $ demote @si) $ T.getComparableProofS s+ ( maybeToRight (NotWellTyped (demote @si) T.BtNotComparable) $ T.getComparableProofS s ) $ Right Dict STOperation -> Right Dict- STContract s -> fromEDict (getWTP_ s) (Right Dict)- STPair s1 s2 -> fromEDict (getWTP_ s1) $ fromEDict (getWTP_ s2) $ Right Dict- STOr s1 s2 -> fromEDict (getWTP_ s1) $ fromEDict (getWTP_ s2) $ Right Dict- STLambda s1 s2 -> fromEDict (getWTP_ s1) $ fromEDict (getWTP_ s2) $ Right Dict+ STContract (s :: Sing si) ->+ withSingI s $ fromEDict (getWTP_ s) $+ fromEDict+ ( maybeToRight (NotWellTyped (demote @si) T.BtIsOperation) $ T.opAbsense s+ ) $ Right Dict++ STTicket (s :: Sing si) ->+ withSingI s $ fromEDict (getWTP_ s) $+ fromEDict+ ( maybeToRight (NotWellTyped (demote @si) T.BtNotComparable) $ T.getComparableProofS s+ ) $ Right Dict+ STPair s1 s2 ->+ withSingI s1 $+ withSingI s2 $+ fromEDict (getWTP_ s1) $+ fromEDict (getWTP_ s2) $ Right Dict+ STOr s1 s2 ->+ withSingI s1 $+ withSingI s2 $+ fromEDict (getWTP_ s1) $+ fromEDict (getWTP_ s2) $ Right Dict+ STLambda s1 s2 ->+ withSingI s1 $+ withSingI s2 $+ fromEDict (getWTP_ s1) $ fromEDict (getWTP_ s2) $ Right Dict STMap (s1 :: Sing si) s2 ->+ withSingI s1 $+ withSingI s2 $ fromEDict (getWTP_ s1) $ fromEDict (getWTP_ s2) $ fromEDict- ( maybeToRight (NotWellTyped $ demote @si) $ T.getComparableProofS s1+ ( maybeToRight (NotWellTyped (demote @si) T.BtNotComparable) $ T.getComparableProofS s1 ) $ Right Dict- STBigMap (s1 :: Sing si) s2 ->+ STBigMap (s1 :: Sing si) (s2 :: Sing si2) ->+ withSingI s1 $+ withSingI s2 $ fromEDict (getWTP_ s1) $ fromEDict (getWTP_ s2) $ fromEDict- ( maybeToRight (NotWellTyped $ demote @si) $ T.getComparableProofS s1- ) $ Right Dict+ ( maybeToRight (NotWellTyped (demote @si) T.BtNotComparable) $ T.getComparableProofS s1+ ) $+ fromEDict+ ( maybeToRight (NotWellTyped (demote @si2) T.BtIsOperation) $ T.opAbsense s2+ ) $+ fromEDict+ ( maybeToRight (NotWellTyped (demote @si2) T.BtHasBigMap) $ T.bigMapAbsense s2+ ) $ Right Dict STInt -> Right Dict STNat -> Right Dict STString -> Right Dict@@ -272,9 +291,10 @@ STTimestamp -> Right Dict STAddress -> Right Dict STNever -> Right Dict- where- getWTP_ :: forall t1. SingI t1 => Sing t1 -> Either NotWellTyped (Dict (WellTyped t1))- getWTP_ _ = getWTP @t1++-- | Version of 'getWTP' that accepts 'Sing' at term-level.+getWTP_ :: forall t. Sing t -> Either NotWellTyped (Dict (WellTyped t))+getWTP_ s = withSingI s $ getWTP @t -- | Given a type and an action that requires evidence that the type is well typed, -- generate the evidence and execute the action, or else fail with an error.
src/Michelson/TypeCheck/Value.hs view
@@ -10,20 +10,23 @@ import Control.Monad.Except (liftEither, throwError) import Data.Constraint (Dict(..)) import Data.Default (def)+import qualified Data.List.NonEmpty as NE import qualified Data.Map as M import qualified Data.Set as S-import Data.Singletons (Sing, SingI(..), demote)+import Data.Singletons (Sing, SingI(..), demote, fromSing, withSingI) import Data.Typeable ((:~:)(..))+import Fmt (pretty) import Prelude hiding (EQ, GT, LT) import Michelson.Text import Michelson.TypeCheck.Error (TCError(..), TCTypeError(..)) import Michelson.TypeCheck.Helpers import Michelson.TypeCheck.TypeCheck- (SomeParamType(..), TcInstrHandler, TcOriginatedContracts, TypeCheckInstr, throwingTCError)+ (SomeParamType(..), TcInstrHandler, TcOriginatedContracts, TypeCheckInstr, TypeCheckOptions(..),+ throwingTCError) import Michelson.TypeCheck.Types import Michelson.Typed- (EpAddress(..), KnownT, Notes(..), SingT(..), Value'(..), fromSingT, starNotes)+ (EpAddress(..), Notes(..), SingT(..), Value'(..), starNotes) import qualified Michelson.Typed as T import qualified Michelson.Untyped as U import Tezos.Address (Address(..))@@ -67,41 +70,41 @@ (U.ValueInt i, STInt) -> pure $ T.VInt i (v@(U.ValueInt i), t@STNat) | i >= 0 -> pure $ VNat (fromInteger i)- | otherwise -> tcFailedOnValue v (fromSingT t) "" (Just NegativeNat)+ | otherwise -> tcFailedOnValue v (fromSing t) "" (Just NegativeNat) (v@(U.ValueInt i), t@STMutez) -> case mkMutez $ fromInteger i of Just m -> pure $ VMutez m- Nothing -> tcFailedOnValue v (fromSingT t) "" (Just InvalidTimestamp)+ Nothing -> tcFailedOnValue v (fromSing t) "" (Just InvalidTimestamp) (U.ValueString s, STString) -> pure $ VString s (v@(U.ValueString s), t@STAddress) -> case T.parseEpAddress (unMText s) of Right addr -> pure $ VAddress addr- Left err -> tcFailedOnValue v (fromSingT t) "" (Just $ InvalidAddress err)+ Left err -> tcFailedOnValue v (fromSing t) "" (Just $ InvalidAddress err) (v@(U.ValueBytes b), t@STAddress) -> case T.parseEpAddressRaw (U.unInternalByteString b) of Right addr -> pure $ VAddress addr- Left err -> tcFailedOnValue v (fromSingT t) "" (Just $ InvalidAddress err)+ Left err -> tcFailedOnValue v (fromSing t) "" (Just $ InvalidAddress err) (v@(U.ValueString s), t@STKeyHash) -> case parseKeyHash (unMText s) of Right kHash -> pure $ VKeyHash kHash- Left err -> tcFailedOnValue v (fromSingT t) "" (Just $ InvalidKeyHash err)+ Left err -> tcFailedOnValue v (fromSing t) "" (Just $ InvalidKeyHash err) (v@(U.ValueBytes b), t@STKeyHash) -> case parseKeyHashRaw (U.unInternalByteString b) of Right kHash -> pure $ VKeyHash kHash- Left err -> tcFailedOnValue v (fromSingT t) "" (Just $ InvalidKeyHash err)+ Left err -> tcFailedOnValue v (fromSing t) "" (Just $ InvalidKeyHash err) (U.ValueInt i, STBls12381Fr) -> pure $ VBls12381Fr (fromIntegral i) (v@(U.ValueBytes b), t@STBls12381Fr) -> case BLS.fromMichelsonBytes (U.unInternalByteString b) of Right val -> pure $ VBls12381Fr val- Left err -> tcFailedOnValue v (fromSingT t) "" (Just $ InvalidBls12381Object err)+ Left err -> tcFailedOnValue v (fromSing t) "" (Just $ InvalidBls12381Object err) (v@(U.ValueBytes b), t@STBls12381G1) -> case BLS.fromMichelsonBytes (U.unInternalByteString b) of Right val -> pure $ VBls12381G1 val- Left err -> tcFailedOnValue v (fromSingT t) "" (Just $ InvalidBls12381Object err)+ Left err -> tcFailedOnValue v (fromSing t) "" (Just $ InvalidBls12381Object err) (v@(U.ValueBytes b), t@STBls12381G2) -> case BLS.fromMichelsonBytes (U.unInternalByteString b) of Right val -> pure $ VBls12381G2 val- Left err -> tcFailedOnValue v (fromSingT t) "" (Just $ InvalidBls12381Object err)+ Left err -> tcFailedOnValue v (fromSing t) "" (Just $ InvalidBls12381Object err) (v@(U.ValueString s), t@STTimestamp) -> case parseTimestamp $ unMText s of Just tstamp -> pure $ VTimestamp tstamp- Nothing -> tcFailedOnValue v (fromSingT t) "" (Just InvalidTimestamp)+ Nothing -> tcFailedOnValue v (fromSing t) "" (Just InvalidTimestamp) (U.ValueInt i, STTimestamp) -> pure $ VTimestamp (timestampFromSeconds i) (U.ValueBytes (U.InternalByteString s), STBytes) -> pure $ VBytes s (U.ValueTrue, STBool) -> pure $ VBool True@@ -123,63 +126,119 @@ pure $ VChainId ci (cv@(U.ValueString (T.parseEpAddress . unMText -> Right addr))- , STContract pc) -> typecheckContractValue cv addr pc+ , STContract pc) -> withSingI pc $ typecheckContractValue cv addr pc (cv@(U.ValueBytes (T.parseEpAddressRaw . U.unInternalByteString -> Right addr))- , STContract pc) -> typecheckContractValue cv addr pc+ , STContract pc) -> withSingI pc $ typecheckContractValue cv addr pc + (cv, s@(STTicket vt)) -> withSingI vt $ lift (asks tcStrict) >>= \case+ -- Note [Tickets forging]+ -- Normally, ticket values cannot be constructed manually (i.e. forged)+ -- by design, and the only valid way to make a ticket is calling+ -- @TICKET@ instruction.+ --+ -- However @tezos-client run@ adds an exception, it allows passing a+ -- manually constructed ticket value as parameter or initial storage.+ True ->+ tcFailedOnValue cv (demote @tz)+ "ticket values cannot be forged in real operations"+ Nothing+ False -> case cv of+ U.ValuePair addrV (U.ValuePair datV amV) -> withComparable vt cv s $ do+ addrValue <- doTypeCheckVal @'T.TAddress addrV+ dat <- doTypeCheckVal datV+ amountValue <- doTypeCheckVal @'T.TNat amV+ case (addrValue, amountValue) of+ (VAddress (EpAddress addr ep), VNat am) -> do+ unless (U.isDefEpName ep) $+ tcFailedOnValue cv (demote @tz)+ "it is pointless to provide an address with entrypoint as a \+ \ticketer, we do not support that"+ Nothing+ -- ↑ Tezos allows passing addresses with entrypoint, but it is+ -- not possible to sanely work with them after that anyway,+ -- since @TICKET@ instruction (the only valid way of constructing+ -- tickets in real run) uses @SELF_ADDRESS@ result as ticketer.+ return $ VTicket addr dat am+ _ ->+ tcFailedOnValue cv (demote @tz)+ "ticket type expects a value of type `(pair address <data> nat)`"+ Nothing+ (U.ValueUnit, STUnit) -> pure $ VUnit- (U.ValuePair ml mr, STPair _ _) -> do+ (U.ValuePair ml mr, STPair lt rt) -> withSingI lt $ withSingI rt $ do l <- doTypeCheckVal ml r <- doTypeCheckVal mr pure $ VPair (l, r)- (U.ValueLeft ml, STOr{}) -> do+ (U.ValueLeft ml, STOr lt rt) -> withSingI lt $ withSingI rt $ do l <- doTypeCheckVal ml pure $ VOr (Left l)- (U.ValueRight mr, STOr{}) -> do+ (U.ValueRight mr, STOr lt rt) -> withSingI lt $ withSingI rt $ do r <- doTypeCheckVal mr pure $ VOr (Right r)- (U.ValueSome mv, STOption{}) -> do+ (U.ValueSome mv, STOption op) -> withSingI op $ do v <- doTypeCheckVal mv pure $ VOption (Just v)- (U.ValueNone, STOption _) -> do+ (U.ValueNone, STOption op) -> withSingI op $ do pure $ VOption Nothing - (U.ValueNil, STList _) ->+ (U.ValueNil, STList l) -> withSingI l $ pure $ T.VList [] - (U.ValueSeq (toList -> mels), STList _) -> do+ -- If ValueSeq contains at least 2 elements, it can be type checked as a+ -- right combed pair.+ (U.ValueSeq vals@(_ :| (_ : _)), STPair l r) ->+ withSingI l $ withSingI r $ doTypeCheckVal $ seqToRightCombedPair vals++ (U.ValueSeq (toList -> mels), STList l) -> withSingI l $ do els <- typeCheckValsImpl mels pure $ VList els - (U.ValueNil, STSet (s :: Sing st)) -> do+ (U.ValueNil, STSet (s :: Sing st)) -> withSingI s $ do instrPos <- ask case T.getComparableProofS s of Just Dict -> pure (T.VSet S.empty) Nothing -> throwError $ TCFailedOnValue uvalue (demote @st) "Non comparable types are not allowed in Sets" instrPos (Just $ UnsupportedTypeForScope (demote @st) T.BtNotComparable) - (sq@(U.ValueSeq (toList -> mels)), s@(STSet (vt :: Sing st))) -> withComparable vt sq s $ do+ (sq@(U.ValueSeq (toList -> mels)), s@(STSet (vt :: Sing st))) ->+ withComparable vt sq s $ withSingI vt $ do instrPos <- ask els <- typeCheckValsImpl mels elsS <- liftEither $ S.fromDistinctAscList <$> ensureDistinctAsc id els- `onFirst` \msg -> TCFailedOnValue sq (fromSingT vt) msg instrPos Nothing+ `onFirst` \msg -> TCFailedOnValue sq (fromSing vt) msg instrPos Nothing pure $ VSet elsS - (v@U.ValueNil, s@(STMap (st :: Sing st) _)) -> withComparable st v s $ pure $ T.VMap M.empty+ (v@U.ValueNil, s@(STMap (st :: Sing st) vt)) ->+ withSingI st $ withSingI vt $ withComparable st v s $ pure $ T.VMap M.empty - (sq@(U.ValueMap (toList -> mels)), s@(STMap (kt :: Sing st) _)) -> withComparable kt sq s $ do+ (sq@(U.ValueMap (toList -> mels)), s@(STMap (kt :: Sing st) vt)) ->+ withSingI kt $ withSingI vt $ withComparable kt sq s $ do keyOrderedElts <- typeCheckMapVal mels sq kt pure $ VMap (M.fromDistinctAscList keyOrderedElts) - (v@U.ValueNil, s@(STBigMap (st :: Sing st) _)) ->- withComparable st v s $ pure $ T.VBigMap M.empty+ (v@U.ValueNil, s@(STBigMap (st1 :: Sing st) (st2 :: Sing st2))) ->+ withSingI st1 $ withSingI st2 $ withComparable st1 v s $ withBigMapAbsence st2 v s $+ pure $ VBigMap Nothing M.empty - (sq@(U.ValueMap (toList -> mels)), s@(STBigMap (kt :: Sing st) _)) -> withComparable kt sq s $ do- keyOrderedElts <- typeCheckMapVal mels sq kt- pure $ VBigMap (M.fromDistinctAscList keyOrderedElts)+ (sq@(U.ValueMap (toList -> mels)), s@(STBigMap (kt :: Sing st) (vt :: Sing vt))) ->+ withSingI kt $ withSingI vt $+ withComparable kt sq s $ withBigMapAbsence vt sq s $ do+ keyOrderedElts <- typeCheckMapVal mels sq kt+ pure $ VBigMap Nothing (M.fromDistinctAscList keyOrderedElts) - (v, STLambda (_ :: Sing it) (_ :: Sing ot)) -> do+ -- `{ {} }` can be typechecked either as `VLam` or `VList`.+ (U.ValueLambda s, (STList l :: Sing st)) -> withSingI l $+ case emptyLambdaAsList s of+ Just xs -> doTypeCheckVal @st xs+ Nothing -> tcFailedOnValue uvalue (demote @st) "" Nothing++ (U.ValueSeq s, ((STLambda (i :: Sing inp) (o :: Sing out))) :: Sing l) ->+ withSingI i $ withSingI o $ case emptyListAsLambda s of+ Just xs -> doTypeCheckVal @l xs+ Nothing -> tcFailedOnValue uvalue (demote @l) "" Nothing++ (v, STLambda (var :: Sing it) (b :: Sing ot)) -> withSingI var $ withSingI b $ do mp <- case v of U.ValueNil -> pure [] U.ValueLambda mp -> pure $ toList mp@@ -198,8 +257,39 @@ AnyOutInstr lam -> pure $ VLam (T.RfAlwaysFails lam) - (v, t) -> tcFailedOnValue v (fromSingT t) "unknown value" Nothing+ (v, t) -> tcFailedOnValue v (fromSing t) "unknown value" Nothing + seqToRightCombedPair :: (NonEmpty $ U.Value) -> U.Value+ seqToRightCombedPair (x :| [y]) = U.ValuePair x y+ seqToRightCombedPair (x :| xs) = U.ValuePair x $ seqToRightCombedPair (NE.fromList xs)++ -- Converts a lambda containing only empty 'SeqEx's (possibly nested)+ -- to a list of empty lists.+ emptyLambdaAsList :: NonEmpty U.ExpandedOp -> Maybe U.Value+ emptyLambdaAsList ops =+ let+ opToMaybeList :: U.ExpandedOp -> Maybe U.Value+ opToMaybeList = \case+ U.SeqEx [] -> Just U.ValueNil+ U.SeqEx xs -> U.ValueSeq . NE.fromList <$> traverse opToMaybeList xs+ U.PrimEx {} -> Nothing+ U.WithSrcEx _ i -> opToMaybeList i+ in+ U.ValueSeq <$> traverse opToMaybeList ops++ -- Converts a list containing only empty lists (possibly nested)+ -- to a lambda of empty 'SeqEx's.+ emptyListAsLambda :: NonEmpty U.Value -> Maybe U.Value+ emptyListAsLambda ops =+ let+ listToMaybeOp :: U.Value -> Maybe U.ExpandedOp+ listToMaybeOp = \case+ U.ValueNil -> Just $ U.SeqEx []+ U.ValueSeq xs -> U.SeqEx . toList <$> traverse listToMaybeOp xs+ _ -> Nothing+ in+ U.ValueLambda <$> traverse listToMaybeOp ops+ withWTP :: forall t a. SingI t => U.Value@@ -207,8 +297,8 @@ -> TypeCheckInstr a withWTP uvalue fn = case getWTP @t of Right Dict -> fn- Left (NotWellTyped t) -> tcFailedOnValue uvalue (fromSingT $ sing @ty)- ("Value is not well typed: " <> show t) Nothing+ Left (NotWellTyped t cause) -> tcFailedOnValue uvalue (demote @ty)+ ("Value is not well typed: '" <> show t <> "' because it " <> pretty cause) Nothing typeCheckValsImpl :: forall t . (SingI t)@@ -222,33 +312,33 @@ -- It return list of pairs (key, value) with keys in ascending order -- so it is safe to call @fromDistinctAscList@ on returned list typeCheckMapVal- :: forall kt vt. (SingI kt, SingI vt)+ :: forall kt vt. (SingI vt) => [U.Elt U.ExpandedOp] -> U.Value -> Sing kt -> TypeCheckInstr [(T.Value kt, T.Value vt)]- typeCheckMapVal mels sq kt = withComparable kt sq kt $ do+ typeCheckMapVal mels sq kt = withSingI kt $ withComparable kt sq kt $ do instrPos <- ask ks <- typeCheckValsImpl @kt (map (\(U.Elt k _) -> k) mels) vals <- typeCheckValsImpl @vt (map (\(U.Elt _ v) -> v) mels) ksS <- liftEither $ ensureDistinctAsc id ks- `onFirst` \msg -> TCFailedOnValue sq (fromSingT kt) msg instrPos Nothing+ `onFirst` \msg -> TCFailedOnValue sq (fromSing kt) msg instrPos Nothing pure $ zip ksS vals typecheckContractValue- :: forall cp tz. (Typeable cp, SingI cp, tz ~ 'T.TContract cp)+ :: forall cp tz. (tz ~ 'T.TContract cp) => U.Value -> EpAddress -> Sing cp -> TypeCheckInstr (T.Value tz) typecheckContractValue cv (EpAddress addr epName) pc = do instrPos <- ask- let ensureTypeMatches :: forall t'. KnownT t' => TypeCheckInstr (cp :~: t')+ let ensureTypeMatches :: forall t'. SingI t' => TypeCheckInstr (cp :~: t') ensureTypeMatches = liftEither @_ @TypeCheckInstr $ first (TCFailedOnValue cv (demote @ty) "wrong contract parameter" instrPos . Just) $- eqType @cp @t'+ (withSingI pc $ eqType @cp @t') let unsupportedType :: T.BadTypeForScope -> TCError- unsupportedType reason = TCFailedOnValue cv (fromSingT pc)+ unsupportedType reason = TCFailedOnValue cv (fromSing pc) "Unsupported type in type argument of 'contract' type" instrPos $- Just $ UnsupportedTypeForScope (fromSingT pc) reason+ Just $ UnsupportedTypeForScope (fromSing pc) reason case addr of KeyAddress _ -> do Refl <- ensureTypeMatches @'T.TUnit@@ -280,4 +370,18 @@ Nothing -> do instrPos <- ask liftEither . Left $- TCFailedOnValue uv (fromSingT t) "Require a comparable type here" instrPos Nothing+ TCFailedOnValue uv (fromSing t) "Require a comparable type here" instrPos Nothing++withBigMapAbsence+ :: forall a (t :: T.T) ty. Sing a+ -> U.Value+ -> Sing t+ -> (T.HasNoBigMap a => TypeCheckInstr ty)+ -> TypeCheckInstr ty+withBigMapAbsence s uv t act = case T.bigMapAbsense s of+ Just Dict -> act+ Nothing -> do+ instrPos <- ask+ liftEither . Left $+ TCFailedOnValue uv (fromSing t) "Require a type which doesn't contain `big_map` here"+ instrPos Nothing
src/Michelson/Typed.hs view
@@ -12,6 +12,7 @@ import Michelson.Typed.Convert as Exports import Michelson.Typed.Doc as Exports import Michelson.Typed.Entrypoints as Exports+import Michelson.Typed.Existential as Exports import Michelson.Typed.Extract as Exports import Michelson.Typed.Haskell as Exports import Michelson.Typed.Instr as Exports
src/Michelson/Typed/Aliases.hs view
@@ -4,8 +4,6 @@ module Michelson.Typed.Aliases ( Value- , SomeValue- , SomeConstrainedValue , Operation ) where @@ -13,6 +11,4 @@ import Michelson.Typed.Value type Value = Value' Instr-type SomeValue = SomeValue' Instr-type SomeConstrainedValue = SomeConstrainedValue' Instr type Operation = Operation' Instr
src/Michelson/Typed/Annotation.hs view
@@ -29,7 +29,7 @@ , notesT ) where -import Data.Singletons (Sing, SingI(..))+import Data.Singletons (Sing, SingI(..), fromSing, withSingI) import Fmt (Buildable(..), (+|), (|+)) import Text.PrettyPrint.Leijen.Text (Doc, (<+>)) import qualified Text.Show@@ -39,7 +39,8 @@ import Michelson.Typed.Sing import Michelson.Typed.T (T(..)) import Michelson.Untyped.Annotation- (Annotation, FieldAnn, TypeAnn, VarAnn, convergeVarAnns, fullAnnSet, noAnn, singleAnnSet, unifyAnn, unifyPairFieldAnn)+ (Annotation, FieldAnn, TypeAnn, VarAnn, convergeVarAnns, fullAnnSet, noAnn, singleAnnSet,+ unifyAnn, unifyPairFieldAnn) import Util.TH import Util.Typeable @@ -58,6 +59,7 @@ NTSet :: TypeAnn -> Notes t -> Notes ('TSet t) NTOperation :: TypeAnn -> Notes 'TOperation NTContract :: TypeAnn -> Notes t -> Notes ('TContract t)+ NTTicket :: TypeAnn -> Notes t -> Notes ('TTicket t) NTPair :: TypeAnn -> FieldAnn -> FieldAnn -> VarAnn -> VarAnn -> Notes p -> Notes q -> Notes ('TPair p q)@@ -114,6 +116,7 @@ NTSet ta nt -> "NTSet" <+> rendT ta <+> rendN nt NTOperation ta -> "NTOperation" <+> rendT ta NTContract ta nt -> "NTContract" <+> rendT ta <+> rendN nt+ NTTicket ta nt -> "NTTicket" <+> rendT ta <+> rendN nt NTPair ta fa1 fa2 va1 va2 np nq -> "NTPair" <+> rendTFV2 ta fa1 fa2 va1 va2 <+> rendN np <+> rendN nq NTOr ta fa1 fa2 np nq -> "NTOr" <+> rendTF2 ta fa1 fa2 <+> rendN np <+> rendN nq NTLambda ta np nq -> "NTLambda" <+> rendT ta <+> rendN np <+> rendN nq@@ -141,7 +144,7 @@ -- | Get term-level type of notes. notesT :: SingI t => Notes t -> T-notesT = fromSingT . notesSing+notesT = fromSing . notesSing -- | In memory of `NStar` constructor. -- Generates notes with no annotations.@@ -165,15 +168,21 @@ STSignature -> NTSignature noAnn STChainId -> NTChainId noAnn STOperation -> NTOperation noAnn- STSet _ -> NTSet noAnn starNotes- STList _ -> NTList noAnn starNotes- STOption _ -> NTOption noAnn starNotes- STContract _ -> NTContract noAnn starNotes- STMap _ _ -> NTMap noAnn starNotes starNotes- STBigMap _ _ -> NTBigMap noAnn starNotes starNotes- STPair _ _ -> NTPair noAnn noAnn noAnn noAnn noAnn starNotes starNotes- STOr _ _ -> NTOr noAnn noAnn noAnn starNotes starNotes- STLambda _ _ -> NTLambda noAnn starNotes starNotes+ STSet t -> NTSet noAnn (withSingI t starNotes)+ STList t -> NTList noAnn (withSingI t starNotes)+ STOption t -> NTOption noAnn (withSingI t starNotes)+ STContract t -> NTContract noAnn (withSingI t starNotes)+ STTicket t -> NTTicket noAnn (withSingI t starNotes)+ STMap t t' ->+ NTMap noAnn (withSingI t starNotes) (withSingI t' starNotes)+ STBigMap t t' ->+ NTBigMap noAnn (withSingI t starNotes) (withSingI t' starNotes)+ STPair t t' ->+ NTPair noAnn noAnn noAnn noAnn noAnn (withSingI t starNotes) (withSingI t' starNotes)+ STOr t t' ->+ NTOr noAnn noAnn noAnn (withSingI t starNotes) (withSingI t' starNotes)+ STLambda t t' ->+ NTLambda noAnn (withSingI t starNotes) (withSingI t' starNotes) -- | Checks if no annotations are present. isStar :: SingI t => Notes t -> Bool@@ -213,6 +222,8 @@ NTOperation <$> convergeAnns a b (NTContract a n, NTContract b m) -> NTContract <$> convergeAnns a b <*> converge n m+ (NTTicket a n, NTTicket b m) ->+ NTTicket <$> convergeAnns a b <*> converge n m (NTPair a pF qF pV qV pN qN, NTPair b pG qG pW qW pM qM) -> NTPair <$> convergeAnns a b <*> convergeAnns pF pG <*> convergeAnns qF qG@@ -251,6 +262,7 @@ NTSet _ n1 -> NTSet nt n1 NTOperation _ -> NTOperation nt NTContract _ n1 -> NTContract nt n1+ NTTicket _ n1 -> NTTicket nt n1 NTPair _ n1 n2 n3 n4 n5 n6 -> NTPair nt n1 n2 n3 n4 n5 n6 NTOr _ n1 n2 n3 n4 -> NTOr nt n1 n2 n3 n4 NTLambda _ n1 n2 -> NTLambda nt n1 n2@@ -289,7 +301,7 @@ => Annotation tag -> Annotation tag -> Either AnnConvergeError (Annotation tag) convergeAnns = convergeAnnsImpl unifyAnn --- | Converge two field notes in CAR or CDR, given that one of them may be a+-- | Converge two field notes in CAR, CDR or UNPAIR, given that one of them may be a -- special annotation. convergeDestrAnns :: FieldAnn -> FieldAnn -> Either AnnConvergeError FieldAnn convergeDestrAnns = convergeAnnsImpl unifyPairFieldAnn
src/Michelson/Typed/Convert.hs view
@@ -9,8 +9,11 @@ , convertContractCode , convertContract , instrToOps+ , instrToOpsOptimized , untypeDemoteT , untypeValue+ , untypeValueHashable+ , untypeValueOptimized -- Helper for generating documentation , sampleTypedValue@@ -19,9 +22,11 @@ , flattenEntrypoints ) where +import qualified Data.ByteArray as ByteArray import Data.Constraint (Dict(..))+import Data.List.NonEmpty ((<|)) import qualified Data.Map as Map-import Data.Singletons (Sing, demote)+import Data.Singletons (Sing, demote, withSingI) import Data.Vinyl (Rec(..)) import Fmt (Buildable(..), Builder, blockListF, fmt, indentF, listF, pretty, unlinesF) @@ -36,11 +41,18 @@ import Michelson.Typed.T (T(..)) import Michelson.Typed.Value import qualified Michelson.Untyped as U-import Tezos.Core (mformatChainId, parseChainId, timestampFromSeconds, unMutez, unsafeMkMutez)+import Michelson.Untyped.Annotation (Annotation(unAnnotation))+import Tezos.Address (Address(..), ContractHash(..))+import Tezos.Core+ (ChainId(unChainId), mformatChainId, parseChainId, timestampFromSeconds, timestampToSeconds,+ unMutez, unsafeMkMutez) import Tezos.Crypto import qualified Tezos.Crypto.BLS12381 as BLS-import Util.Peano-import Util.Typeable+import qualified Tezos.Crypto.Ed25519 as Ed25519+import qualified Tezos.Crypto.P256 as P256+import qualified Tezos.Crypto.Secp256k1 as Secp256k1+import Util.PeanoNatural (fromPeanoNatural)+import Util.Sing (eqParamSing, eqParamSing2) convertParamNotes :: SingI cp => ParamNotes cp -> U.ParameterType convertParamNotes (ParamNotes notes rootAnn) =@@ -57,26 +69,46 @@ , entriesOrder = U.canonicalEntriesOrder } -convertContract- :: forall param store . (SingI param, SingI store)- => Contract param store -> U.Contract-convertContract fc =+convertContract :: Contract param store -> U.Contract+convertContract fc@Contract{} = let c = convertContractCode (cCode fc) in c { U.contractParameter = convertParamNotes (cParamNotes fc) , U.contractStorage = mkUType (cStoreNotes fc) , U.entriesOrder = cEntriesOrder fc } +-- Note: if you change this type, check 'untypeValueImpl' wildcard patterns.+data UntypingOptions+ = Readable+ -- ^ Convert value to human-readable representation+ | Optimized+ -- ^ Convert value to optimized representation+ | Hashable+ -- ^ Like 'Optimized', but without list notation for pairs.+ -- Created to match 'tezos-client hash data' behavior for typed values.+ -- See https://gitlab.com/morley-framework/morley/-/issues/611+ deriving stock (Eq, Show)++untypeValue :: (SingI t, HasNoOp t) => Value' Instr t -> U.Value+untypeValue = untypeValueImpl Readable++untypeValueHashable :: (SingI t, HasNoOp t) => Value' Instr t -> U.Value+untypeValueHashable = untypeValueImpl Hashable++untypeValueOptimized :: (SingI t, HasNoOp t) => Value' Instr t -> U.Value+untypeValueOptimized = untypeValueImpl Optimized+ -- | Convert a typed 'Val' to an untyped 'Value'. -- -- For full isomorphism type of the given 'Val' should not contain -- 'TOperation' - a compile error will be raised otherwise. -- You can analyse its presence with 'checkOpPresence' function.-untypeValue ::+untypeValueImpl :: forall t . (SingI t, HasNoOp t)- => Value' Instr t+ => UntypingOptions+ -> Value' Instr t -> U.Value-untypeValue val = case (val, sing @t) of+untypeValueImpl opts val = case (val, sing @t) of (VInt i, _) -> U.ValueInt i (VNat i, _) -> U.ValueInt $ toInteger i (VString s, _) -> U.ValueString s@@ -84,106 +116,192 @@ (VMutez m, _) -> U.ValueInt $ toInteger $ unMutez m (VBool True, _) -> U.ValueTrue (VBool False, _) -> U.ValueFalse- (VKeyHash h, _) -> U.ValueString $ mformatKeyHash h- -- Here we intentionally diverge from the reference implementation.- -- Tezos prints bls12_381_fr as bytes, but printing a number is more convenient- -- (numbers are shorter, and Tezos can parse numbers to bls12_381_fr)- (VBls12381Fr v, _) -> U.ValueInt $ toInteger v- (VBls12381G1 v, _) -> U.ValueBytes $ U.InternalByteString $ BLS.toMichelsonBytes v- (VBls12381G2 v, _) -> U.ValueBytes $ U.InternalByteString $ BLS.toMichelsonBytes v- (VTimestamp t, _) -> U.ValueString $ mkMTextUnsafe $ pretty t- (VAddress a, _) -> U.ValueString $ mformatEpAddress a+ (VKeyHash h, _) ->+ case opts of+ Readable -> U.ValueString $ mformatKeyHash h+ _ -> U.ValueBytes $ U.InternalByteString $ keyHashToBytes h+ (VBls12381Fr v, _) ->+ case opts of+ Readable -> U.ValueInt $ toInteger v+ _ -> U.ValueBytes . U.InternalByteString $ BLS.toMichelsonBytes v+ (VBls12381G1 v, _) ->+ U.ValueBytes . U.InternalByteString $ BLS.toMichelsonBytes v+ (VBls12381G2 v, _) ->+ U.ValueBytes . U.InternalByteString $ BLS.toMichelsonBytes v+ (VTimestamp t, _) ->+ case opts of+ Readable -> U.ValueString . unsafeMkMText $ pretty t+ _ -> U.ValueInt $ timestampToSeconds t+ (VAddress a, _) ->+ case opts of+ Readable -> U.ValueString $ mformatEpAddress a+ _ -> U.ValueBytes . U.InternalByteString $ encodeEpAddress a (VKey b, _) ->- U.ValueString $ mformatPublicKey b+ case opts of+ Readable -> U.ValueString $ mformatPublicKey b+ _ -> U.ValueBytes . U.InternalByteString $ keyToBytes b (VUnit, _) -> U.ValueUnit (VSignature b, _) ->- U.ValueString $ mformatSignature b+ case opts of+ Readable -> U.ValueString $ mformatSignature b+ _ -> U.ValueBytes . U.InternalByteString $ signatureToBytes b (VChainId b, _) ->- U.ValueString $ mformatChainId b+ case opts of+ Readable -> U.ValueString $ mformatChainId b+ _ ->+ U.ValueBytes . U.InternalByteString $ ByteArray.convert (unChainId b) (VOption (Just x), STOption _) ->- U.ValueSome (untypeValue x)+ U.ValueSome (untypeValueImpl opts x) (VOption Nothing, STOption _) -> U.ValueNone (VList l, STList _) ->- vList U.ValueSeq $ map untypeValue l+ vList U.ValueSeq $ map (untypeValueImpl opts) l (VSet s, STSet (st :: SingT st)) -> case checkOpPresence st of- OpAbsent -> vList U.ValueSeq $ map (untypeValue @st) $ toList s+ OpAbsent -> vList U.ValueSeq $ map (untypeValueImpl @st opts) $ toList s (VContract addr sepc, _) ->- U.ValueString . mformatEpAddress $ EpAddress addr (sepcName sepc)-- (VPair (l, r), STPair lt _) ->+ case opts of+ Readable ->+ U.ValueString . mformatEpAddress $ EpAddress addr (sepcName sepc)+ _ -> U.ValueBytes . U.InternalByteString . encodeEpAddress $+ EpAddress addr (sepcName sepc)+ (VTicket s v a, _) ->+ case valueTypeSanity v of+ Dict ->+ let us = untypeValueImpl opts $ VAddress (EpAddress s DefEpName)+ uv = untypeValueImpl opts v+ ua = untypeValueImpl opts $ VNat a+ in case opts of+ Optimized -> U.ValueSeq $ us :| [uv, ua]+ _ -> U.ValuePair us (U.ValuePair uv ua)+ p@(VPair (l, r), STPair lt rt) ->+ withSingI lt $+ withSingI rt $ case checkOpPresence lt of- OpAbsent -> U.ValuePair (untypeValue l) (untypeValue r)+ OpAbsent -> case opts of+ Optimized -> U.ValueSeq $ pairToSeq p+ _ -> U.ValuePair (untypeValueImpl opts l) (untypeValueImpl opts r) (VOr (Left x), STOr lt _) -> case checkOpPresence lt of- OpAbsent -> U.ValueLeft (untypeValue x)+ OpAbsent -> U.ValueLeft (untypeValueImpl opts x) (VOr (Right x), STOr lt _) -> case checkOpPresence lt of- OpAbsent -> U.ValueRight (untypeValue x)+ OpAbsent -> U.ValueRight (untypeValueImpl opts x) (VLam (rfAnyInstr -> ops :: Instr '[inp] '[out]), _) ->- vList U.ValueLambda $ instrToOps ops+ vList U.ValueLambda $ instrToOpsImpl opts ops (VMap m, STMap kt vt) -> case (checkOpPresence kt, checkOpPresence vt) of (OpAbsent, OpAbsent) -> vList U.ValueMap $ Map.toList m <&> \(k, v) ->- U.Elt (untypeValue k) (untypeValue v)+ U.Elt (untypeValueImpl opts k) (untypeValueImpl opts v) - (VBigMap m, STBigMap kt vt) ->+ (VBigMap _ m, STBigMap kt vt) -> case (checkOpPresence kt, checkOpPresence vt) of (OpAbsent, OpAbsent) -> vList U.ValueMap $ Map.toList m <&> \(k, v) ->- U.Elt (untypeValue k) (untypeValue v)+ U.Elt (untypeValueImpl opts k) (untypeValueImpl opts v) where vList ctor = maybe U.ValueNil ctor . nonEmpty + pairToSeq :: (SingI ty, HasNoOp ty)+ => (Value ty, Sing ty)+ -> NonEmpty U.Value+ pairToSeq = \case+ (VPair (a, b), STPair l r) -> withSingI l $ withSingI r $+ case checkOpPresence l of+ OpAbsent -> untypeValueImpl opts a <| pairToSeq (b, r)+ (v, _) -> untypeValueImpl opts v :| []++ keyHashToBytes :: KeyHash -> ByteString+ keyHashToBytes kh = (<> (khBytes kh)) $+ case khTag kh of+ KeyHashEd25519 -> "\x00"+ KeyHashSecp256k1 -> "\x01"+ KeyHashP256 -> "\x02"++ keyToBytes :: PublicKey -> ByteString+ keyToBytes = \case+ PublicKeyEd25519 pk -> "\x00" <> Ed25519.publicKeyToBytes pk+ PublicKeySecp256k1 pk -> "\x01" <> Secp256k1.publicKeyToBytes pk+ PublicKeyP256 pk -> "\x02" <> P256.publicKeyToBytes pk++ encodeEpAddress :: EpAddress -> ByteString+ encodeEpAddress (EpAddress addr epName) =+ encodeAddress addr <> encodeEpName epName++ encodeAddress :: Address -> ByteString+ encodeAddress = \case+ KeyAddress keyHash ->+ "\x00" <> keyHashToBytes keyHash+ ContractAddress (ContractHash address) ->+ "\x01" <> address <> "\x00"++ encodeEpName :: EpName -> ByteString+ encodeEpName = encodeUtf8 . unAnnotation . epNameToRefAnn . canonicalize+ where+ canonicalize :: EpName -> EpName+ canonicalize (UnsafeEpName "default") = DefEpName+ canonicalize epName = epName+ untypeDemoteT :: forall (t :: T). SingI t => U.Ty untypeDemoteT = toUType $ demote @t +instrToOpsOptimized :: HasCallStack => Instr inp out -> [U.ExpandedOp]+instrToOpsOptimized = instrToOpsImpl Optimized+ instrToOps :: HasCallStack => Instr inp out -> [U.ExpandedOp]-instrToOps = \case+instrToOps = instrToOpsImpl Readable++instrToOpsImpl :: HasCallStack+ => UntypingOptions+ -> Instr inp out+ -> [U.ExpandedOp]+instrToOpsImpl opts = \case Nop -> []- Seq i1 i2 -> instrToOps i1 <> instrToOps i2+ Seq i1 i2 -> instrToOpsImpl opts i1 <> instrToOpsImpl opts i2 Nested sq -> one $ U.SeqEx $ instrToOps sq- DocGroup _ sq -> instrToOps sq+ DocGroup _ sq -> instrToOpsImpl opts sq+ Fn t sfn i -> [U.PrimEx . U.EXT . U.FN t sfn $ instrToOps i] Ext (ext :: ExtInstr inp) -> (U.PrimEx . U.EXT) <$> extInstrToOps ext- FrameInstr _ i -> instrToOps i+ FrameInstr _ i -> instrToOpsImpl opts i -- TODO [#283] After representation of locations is polished, -- this place should be updated to pass it from typed to untyped ASTs.- WithLoc _ i -> instrToOps i- InstrWithVarAnns _ i -> instrToOps i+ WithLoc _ i -> instrToOpsImpl opts i+ InstrWithVarAnns _ i -> instrToOpsImpl opts i InstrWithNotes proxy n i -> case i of- Nop -> instrToOps i- Seq _ _ -> instrToOps i- Nested _ -> instrToOps i- DocGroup _ _ -> instrToOps i- Ext _ -> instrToOps i- WithLoc _ i0 -> instrToOps (InstrWithNotes proxy n i0)- InstrWithNotes {} -> instrToOps i+ Nop -> instrToOpsImpl opts i+ Seq _ _ -> instrToOpsImpl opts i+ Nested _ -> instrToOpsImpl opts i+ DocGroup _ _ -> instrToOpsImpl opts i+ Ext _ -> instrToOpsImpl opts i+ WithLoc _ i0 -> instrToOpsImpl opts (InstrWithNotes proxy n i0)+ InstrWithNotes {} -> instrToOpsImpl opts i -- For inner instruction, filter out values that we don't want to apply -- annotations to and delegate it's conversion to this function itself. -- If none of the above, convert a single instruction and copy annotations -- to it.- InstrWithVarNotes n0 (InstrWithVarAnns _ i0) -> instrToOps $ InstrWithNotes proxy n $ InstrWithVarNotes n0 i0+ InstrWithVarNotes n0 (InstrWithVarAnns _ i0) ->+ instrToOpsImpl opts $ InstrWithNotes proxy n $ InstrWithVarNotes n0 i0 InstrWithVarNotes n0 i0 -> [U.PrimEx $ handleInstrAnnotateWithVarNotes i0 n n0]- InstrWithVarAnns _ _ -> instrToOps i+ InstrWithVarAnns _ _ -> instrToOpsImpl opts i _ -> [U.PrimEx $ handleInstrAnnotate i n] InstrWithVarNotes n i -> case i of- Nop -> instrToOps i- Seq _ _ -> instrToOps i- Nested _ -> instrToOps i- DocGroup _ _ -> instrToOps i- Ext _ -> instrToOps i- WithLoc _ i0 -> instrToOps (InstrWithVarNotes n i0)- InstrWithNotes p0 n0 (InstrWithVarAnns _ i0) -> instrToOps $ InstrWithNotes p0 n0 $ InstrWithVarNotes n i0+ Nop -> instrToOpsImpl opts i+ Seq _ _ -> instrToOpsImpl opts i+ Nested _ -> instrToOpsImpl opts i+ DocGroup _ _ -> instrToOpsImpl opts i+ Ext _ -> instrToOpsImpl opts i+ WithLoc _ i0 -> instrToOpsImpl opts (InstrWithVarNotes n i0)+ InstrWithNotes p0 n0 (InstrWithVarAnns _ i0) ->+ instrToOpsImpl opts $ InstrWithNotes p0 n0 $ InstrWithVarNotes n i0 InstrWithNotes _ n0 i0 -> [U.PrimEx $ handleInstrAnnotateWithVarNotes i0 n0 n]- InstrWithVarNotes _ _ -> instrToOps i- InstrWithVarAnns _ i0 -> instrToOps $ InstrWithVarNotes n i0+ InstrWithVarNotes _ _ -> instrToOpsImpl opts i+ InstrWithVarAnns _ i0 -> instrToOpsImpl opts $ InstrWithVarNotes n i0 _ -> [U.PrimEx $ handleInstrVarNotes i n] i -> [U.PrimEx $ handleInstr i] where@@ -213,41 +331,44 @@ (U.SOME _ va, NTOption ta _ :& _) -> U.SOME ta va (U.NONE _ va _, (NTOption ta nt :: Notes t) :& _) -> case sing @t of- STOption {} -> U.NONE ta va (mkUType nt)+ STOption t -> U.NONE ta va (withSingI t $ mkUType nt) (U.UNIT _ va, NTUnit ta :& _) -> U.UNIT ta va- (U.PAIR ta va f1 f2, _) -> U.PAIR ta va f1 f2 (U.PAIRN va n, _) -> U.PAIRN va n- (U.CAR va f1, _) -> U.CAR va f1- (U.CDR va f1, _) -> U.CDR va f1- (U.LEFT _ va _ _ _, (NTOr ta f1 f2 _ n2 :: Notes t) :& _) ->+ (U.LEFT ta va fa1 fa2 _, (NTOr _ _ _ _ n2 :: Notes t) :& _) -> case sing @t of- STOr {} -> U.LEFT ta va f1 f2 (mkUType n2)- (U.RIGHT _ va _ _ _, (NTOr ta f1 f2 n1 _ :: Notes t) :& _) ->+ STOr _ rt ->+ U.LEFT ta va fa1 fa2 (withSingI rt $ mkUType n2)+ (U.RIGHT ta va fa1 fa2 _, (NTOr _ _ _ n1 _ :: Notes t) :& _) -> case sing @t of- STOr {} -> U.RIGHT ta va f1 f2 (mkUType n1)+ STOr lt _ ->+ U.RIGHT ta va fa1 fa2 (withSingI lt $ mkUType n1) (U.NIL _ va _, (NTList ta n :: Notes t) :& _) -> case sing @t of- STList {} -> U.NIL ta va (mkUType n)+ STList l -> U.NIL ta va (withSingI l $ mkUType n) (U.EMPTY_SET _ va _, (NTSet ta1 n :: Notes t) :& _) -> case sing @t of- STSet {} -> U.EMPTY_SET ta1 va (mkUType n)+ STSet s -> U.EMPTY_SET ta1 va (withSingI s $ mkUType n) (U.EMPTY_MAP _ va _ _, (NTMap ta1 k n :: Notes t) :& _) -> case sing @t of- STMap {} -> U.EMPTY_MAP ta1 va (mkUType k) (mkUType n)+ STMap kt vt -> U.EMPTY_MAP ta1 va (withSingI kt $ mkUType k) (withSingI vt $ mkUType n) (U.EMPTY_BIG_MAP _ va _ _, (NTBigMap ta1 k n :: Notes t) :& _) -> case sing @t of- STBigMap {} -> U.EMPTY_BIG_MAP ta1 va (mkUType k) (mkUType n)+ STBigMap kt vt -> U.EMPTY_BIG_MAP ta1 va (withSingI kt $ mkUType k) (withSingI vt $ mkUType n) (U.LAMBDA va _ _ ops, (NTLambda _ n1 n2 :: Notes t) :& _) -> case sing @t of- STLambda {} -> U.LAMBDA va (mkUType n1) (mkUType n2) ops+ STLambda v b -> U.LAMBDA va (withSingI v $ mkUType n1) (withSingI b $ mkUType n2) ops (U.CAST va _, n :& _) -> U.CAST va (mkUType n) (U.UNPACK _ va _, (NTOption ta nt :: Notes t) :& _) -> case sing @t of- STOption {} -> U.UNPACK ta va (mkUType nt)+ STOption op -> U.UNPACK ta va (withSingI op $ mkUType nt) (U.CONTRACT va fa _, (NTOption _ (NTContract _ nt :: Notes t) :: Notes t2) :& _) -> case sing @t2 of- STOption STContract {} -> U.CONTRACT va fa (mkUType nt)+ STOption (STContract c) -> U.CONTRACT va fa (withSingI c $ mkUType nt) (U.CONTRACT va fa t, NTOption _ _ :& _) -> U.CONTRACT va fa t+ (U.CAR {}, _) -> instr+ (U.CDR {}, _) -> instr+ (U.PAIR {}, _) -> instr+ (U.UNPAIR {}, _) -> instr (U.APPLY {}, _) -> instr (U.CHAIN_ID {}, _) -> instr (U.EXT _, _) -> instr@@ -326,6 +447,10 @@ (U.ADDRESS _, _) -> instr (U.SELF_ADDRESS _, _) -> instr (U.NEVER, _) -> instr+ (U.TICKET _, _) -> instr+ (U.READ_TICKET _, _) -> instr+ (U.SPLIT_TICKET _, _) -> instr+ (U.JOIN_TICKETS _, _) -> instr _ -> error $ pretty $ unlinesF [ "addInstrNote: Unexpected instruction/annotation combination" , "Instruction:"@@ -361,8 +486,6 @@ U.UNIT ta _ -> U.UNIT ta va U.PAIR ta _ fa1 fa2 -> U.PAIR ta va fa1 fa2 U.PAIRN _ n -> U.PAIRN va n- U.CAR _ fa -> U.CAR va fa- U.CDR _ fa -> U.CDR va fa U.LEFT ta _ fa1 fa2 t -> U.LEFT ta va fa1 fa2 t U.RIGHT ta _ fa1 fa2 t -> U.RIGHT ta va fa1 fa2 t U.NIL ta _ t -> U.NIL ta va t@@ -432,6 +555,10 @@ U.CHAIN_ID _ -> U.CHAIN_ID va U.LEVEL _ -> U.LEVEL va U.SELF_ADDRESS _ -> U.SELF_ADDRESS va+ U.TICKET _ -> U.TICKET va+ U.READ_TICKET _ -> U.READ_TICKET va+ U.SPLIT_TICKET _ -> U.SPLIT_TICKET va+ U.JOIN_TICKETS _ -> U.JOIN_TICKETS va _ -> error $ "addVarNotes: Cannot add single var annotation to instr: " <> (show ins) <> " with " <> show va _ -> error $@@ -449,35 +576,47 @@ (Ext _) -> error "impossible" (Nested _) -> error "impossible" DocGroup{} -> error "impossible"+ Fn t sfn i -> U.EXT . U.FN t sfn $ instrToOpsImpl opts i DROP -> U.DROP- (DROPN s) -> U.DROPN (fromIntegral $ peanoValSing s)+ (DROPN s) -> U.DROPN (fromIntegral $ fromPeanoNatural s) DUP -> U.DUP U.noAnn- (DUPN s) -> U.DUPN U.noAnn (fromIntegral $ peanoValSing s)+ (DUPN s) -> U.DUPN U.noAnn (fromIntegral $ fromPeanoNatural s) SWAP -> U.SWAP- (DIG s) -> U.DIG (fromIntegral $ peanoValSing s)- (DUG s) -> U.DUG (fromIntegral $ peanoValSing s)+ (DIG s) -> U.DIG (fromIntegral $ fromPeanoNatural s)+ (DUG s) -> U.DUG (fromIntegral $ fromPeanoNatural s) i@(PUSH val) | _ :: Instr inp1 (t ': s) <- i ->- let value = untypeValue val+ let value = untypeValueImpl opts val in U.PUSH U.noAnn (untypeDemoteT @t) value i@NONE | _ :: Instr inp1 ('TOption a ': inp1) <- i -> U.NONE U.noAnn U.noAnn (untypeDemoteT @a) SOME -> U.SOME U.noAnn U.noAnn UNIT -> U.UNIT U.noAnn U.noAnn- (IF_NONE i1 i2) -> U.IF_NONE (instrToOps i1) (instrToOps i2)+ (IF_NONE i1 i2) -> U.IF_NONE (instrToOpsImpl opts i1) (instrToOpsImpl opts i2)++ -- `AnnUNPAIR` accepts special var anns, so it carries them inside its constructor,+ -- so we can use them here to re-construct an untyped `U.UNPAIR`.+ -- `AnnPAIR`, on the other hand, doesn't accept special var anns, so the var anns+ -- are carried in the `InstrWithVarNotes` meta-instruction instead.+ --+ -- See: Note [Annotations - Exceptional scenarios] in `Michelson.Typed.Instr`+ --+ -- TODO [#580] AnnPAIR tn fn1 fn2 -> U.PAIR tn U.noAnn fn1 fn2- PAIRN n -> U.PAIRN U.noAnn (fromIntegral $ peanoValSing n)- UNPAIRN n -> U.UNPAIRN (fromIntegral $ peanoValSing n)- (AnnCAR fn) -> U.CAR U.noAnn fn- (AnnCDR fn) -> U.CDR U.noAnn fn+ AnnUNPAIR vn1 vn2 fn1 fn2 -> U.UNPAIR vn1 vn2 fn1 fn2++ PAIRN n -> U.PAIRN U.noAnn (fromIntegral $ fromPeanoNatural n)+ UNPAIRN n -> U.UNPAIRN (fromIntegral $ fromPeanoNatural n)+ (AnnCAR vn fn) -> U.CAR vn fn+ (AnnCDR vn fn) -> U.CDR vn fn i@(AnnLEFT tn fn1 fn2) | _ :: Instr (a ': s) ('TOr a b ': s) <- i -> U.LEFT tn U.noAnn fn1 fn2 (untypeDemoteT @b) i@(AnnRIGHT tn fn1 fn2) | _ :: Instr (b ': s) ('TOr a b ': s) <- i -> U.RIGHT tn U.noAnn fn1 fn2 (untypeDemoteT @a)- (IF_LEFT i1 i2) -> U.IF_LEFT (instrToOps i1) (instrToOps i2)+ (IF_LEFT i1 i2) -> U.IF_LEFT (instrToOpsImpl opts i1) (instrToOpsImpl opts i2) i@NIL | _ :: Instr s ('TList p ': s) <- i -> U.NIL U.noAnn U.noAnn (untypeDemoteT @p) CONS -> U.CONS U.noAnn- (IF_CONS i1 i2) -> U.IF_CONS (instrToOps i1) (instrToOps i2)+ (IF_CONS i1 i2) -> U.IF_CONS (instrToOpsImpl opts i1) (instrToOpsImpl opts i2) SIZE -> U.SIZE U.noAnn i@EMPTY_SET | _ :: Instr s ('TSet e ': s) <- i -> U.EMPTY_SET U.noAnn U.noAnn (U.Ty (U.unwrapT $ untypeDemoteT @e) U.noAnn)@@ -487,24 +626,24 @@ i@EMPTY_BIG_MAP | _ :: Instr s ('TBigMap a b ': s) <- i -> U.EMPTY_BIG_MAP U.noAnn U.noAnn (U.Ty (U.unwrapT $ untypeDemoteT @a) U.noAnn) (untypeDemoteT @b)- (MAP op) -> U.MAP U.noAnn $ instrToOps op- (ITER op) -> U.ITER $ instrToOps op+ (MAP op) -> U.MAP U.noAnn $ instrToOpsImpl opts op+ (ITER op) -> U.ITER $ instrToOpsImpl opts op MEM -> U.MEM U.noAnn GET -> U.GET U.noAnn- GETN n -> U.GETN U.noAnn (fromIntegral $ peanoValSing n)+ GETN n -> U.GETN U.noAnn (fromIntegral $ fromPeanoNatural n) UPDATE -> U.UPDATE U.noAnn- UPDATEN n -> U.UPDATEN U.noAnn (fromIntegral $ peanoValSing n)+ UPDATEN n -> U.UPDATEN U.noAnn (fromIntegral $ fromPeanoNatural n) GET_AND_UPDATE -> U.GET_AND_UPDATE U.noAnn- (IF op1 op2) -> U.IF (instrToOps op1) (instrToOps op2)- (LOOP op) -> U.LOOP (instrToOps op)- (LOOP_LEFT op) -> U.LOOP_LEFT (instrToOps op)+ (IF op1 op2) -> U.IF (instrToOpsImpl opts op1) (instrToOpsImpl opts op2)+ (LOOP op) -> U.LOOP (instrToOpsImpl opts op)+ (LOOP_LEFT op) -> U.LOOP_LEFT (instrToOpsImpl opts op) i@(LAMBDA {}) | LAMBDA (VLam l) :: Instr s ('TLambda i o ': s) <- i ->- U.LAMBDA U.noAnn (untypeDemoteT @i) (untypeDemoteT @o) (instrToOps $ rfAnyInstr l)+ U.LAMBDA U.noAnn (untypeDemoteT @i) (untypeDemoteT @o) (instrToOpsImpl opts $ rfAnyInstr l) EXEC -> U.EXEC U.noAnn APPLY -> U.APPLY U.noAnn- (DIP op) -> U.DIP (instrToOps op)+ (DIP op) -> U.DIP (instrToOpsImpl opts op) (DIPN s op) ->- U.DIPN (fromIntegral $ peanoValSing s) (instrToOps op)+ U.DIPN (fromIntegral $ fromPeanoNatural s) (instrToOpsImpl opts op) FAILWITH -> U.FAILWITH i@CAST | _ :: Instr (a ': s) (a ': s) <- i -> U.CAST U.noAnn (untypeDemoteT @a)@@ -574,9 +713,13 @@ LEVEL -> U.LEVEL U.noAnn SELF_ADDRESS -> U.SELF_ADDRESS U.noAnn NEVER -> U.NEVER+ TICKET -> U.TICKET U.noAnn+ READ_TICKET -> U.READ_TICKET U.noAnn+ SPLIT_TICKET -> U.SPLIT_TICKET U.noAnn+ JOIN_TICKETS -> U.JOIN_TICKETS U.noAnn untypeStackRef :: StackRef s -> U.StackRef-untypeStackRef (StackRef n) = U.StackRef (peanoVal n)+untypeStackRef (StackRef n) = U.StackRef (fromPeanoNatural n) untypePrintComment :: PrintComment s -> U.PrintComment untypePrintComment (PrintComment pc) = U.PrintComment $ map (second untypeStackRef) pc@@ -597,6 +740,7 @@ JustComment com -> one $ U.UCOMMENT com StackTypeComment (Just stack) -> one $ U.UCOMMENT $ pretty (listF stack) StackTypeComment Nothing -> one $ U.UCOMMENT $ fmt "any stack type"+ STACKTYPE s -> one $ U.STACKTYPE s -- 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,@@ -605,14 +749,14 @@ instance Eq (Instr inp out) where i1 == i2 = instrToOps i1 == instrToOps i2 -instance Typeable s => Eq (TestAssert s) where+instance SingI s => Eq (TestAssert s) where TestAssert name1 pattern1 instr1 == TestAssert name2 pattern2 instr2 = and [ name1 == name2- , pattern1 `eqParam1` pattern2- , instr1 `eqParam2` instr2+ , pattern1 `eqParamSing` pattern2+ , instr1 `eqParamSing2` instr2 ] instance (SingI t, HasNoOp t) => Buildable (Value' Instr t) where@@ -644,44 +788,50 @@ STOperation -> Nothing STNever -> Nothing STOption t ->- VOption . Just <$> sampleTypedValue t+ withSingI t $ VOption . Just <$> sampleTypedValue t STList t ->- VList . one <$> sampleTypedValue t- STSet t -> do+ withSingI t $ VList . one <$> sampleTypedValue t+ STSet t -> withSingI t $ do Dict <- comparabilityPresence t VSet . one <$> sampleTypedValue t- STContract t -> do+ STContract t -> withSingI t $ do Dict <- opAbsense t Dict <- nestedBigMapsAbsense t- pure . VContract (eaAddress sampleAddress) $ SomeEpc epcCallRootUnsafe- STPair t1 t2 -> do+ pure . VContract (eaAddress sampleAddress) $ SomeEpc unsafeEpcCallRoot+ STTicket t -> withSingI t $ do+ cmpProof <- comparabilityPresence t+ dat <- sampleTypedValue t+ VNat amount <- sampleTypedValue STNat+ case cmpProof of+ Dict -> return $ VTicket (eaAddress sampleAddress) dat amount+ STPair t1 t2 -> withSingI t1 $ withSingI t2 $ do val1 <- sampleTypedValue t1 val2 <- sampleTypedValue t2 pure $ VPair (val1, val2)- STOr tl tr -> asum+ STOr tl tr -> withSingI tl $ withSingI tr $ asum [ VOr . Left <$> sampleTypedValue tl , VOr . Right <$> sampleTypedValue tr ]- STMap t1 t2 -> do+ STMap t1 t2 -> withSingI t1 $ withSingI t2 $ do val1 <- sampleTypedValue t1 val2 <- sampleTypedValue t2 case checkComparability t1 of CanBeCompared -> pure $ VMap $ Map.fromList [(val1, val2)] CannotBeCompared -> Nothing- STBigMap t1 t2 -> do+ STBigMap t1 t2 -> withSingI t1 $ withSingI t2 $ do val1 <- sampleTypedValue t1 val2 <- sampleTypedValue t2- case checkComparability t1 of- CanBeCompared -> pure $ VBigMap $ Map.fromList [(val1, val2)]- CannotBeCompared -> Nothing- STLambda _ (t2 :: Sing t2) ->+ case (checkComparability t1, bigMapAbsense t2) of+ (CanBeCompared, Just Dict) -> pure $ VBigMap Nothing $ Map.fromList [(val1, val2)]+ _ -> Nothing+ STLambda v (t2 :: Sing t2) -> withSingI v $ withSingI t2 $ case checkScope @(ConstantScope t2) of Right Dict -> do val <- sampleTypedValue t2 pure $ VLam $ RfNormal (DROP `Seq` PUSH val) _ -> pure $ VLam $ RfAlwaysFails (PUSH (VString [mt|lambda sample|]) `Seq` FAILWITH) where- sampleAddress = unsafeParseEpAddress "KT1AEseqMV6fk2vtvQCVyA7ZCaxv7cpxtXdB"+ sampleAddress = unsafeParseEpAddress "KT1AEseqMV6fk2vtvQCVyA7ZCaxv7cpxtXdB" samplePublicKey = fromRight (error "impossible") $ parsePublicKey "edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V" sampleSignature = fromRight (error "impossible") $ parseSignature
src/Michelson/Typed/Doc.hs view
@@ -125,6 +125,13 @@ instance ContainsUpdateableDoc (Instr inp out) where modifyDocEntirely = modifyInstrAllDoc +instance ContainsDoc (Contract cp st) where+ buildDocUnfinalized = buildDocUnfinalized . cCode++instance ContainsUpdateableDoc (Contract cp st) where+ modifyDocEntirely how contract =+ contract{ cCode = modifyInstrAllDoc how (cCode contract) }+ -- | Leave only instructions related to documentation. -- -- Generated documentation for resulting instruction remains the same, but
src/Michelson/Typed/Entrypoints.hs view
@@ -23,9 +23,9 @@ , EpLiftSequence (..) , EntrypointCallT (..) , epcPrimitive- , epcCallRootUnsafe+ , unsafeEpcCallRoot , SomeEntrypointCallT (..)- , sepcCallRootUnsafe+ , unsafeSepcCallRoot , sepcPrimitive , sepcName , ForbidOr@@ -47,15 +47,18 @@ import Control.Monad.Except (throwError) import qualified Data.ByteString as BS import Data.Constraint (Dict(..))+import Data.Singletons (withSingI) import qualified Data.List.NonEmpty as NE import qualified Data.Text as T import Fmt (Buildable(..), hexF, pretty, (+|), (|+))+import Text.PrettyPrint.Leijen.Text ((<+>), int, squotes, punctuate, textStrict) import Michelson.Text import Michelson.Typed.Annotation import Michelson.Typed.Scope import Michelson.Typed.Sing import Michelson.Typed.T+import Michelson.Printer.Util (RenderDoc(..), renderAnyBuildable, buildRenderDoc) import Michelson.Untyped.Annotation import Michelson.Untyped.Entrypoints import Tezos.Address@@ -95,7 +98,7 @@ let t = formatEpAddress ea -- Should be safe because set of characters allowed in annotations -- (and thus in 'EpName') is subset of characters allowed in Michelson strings.- in mkMTextUnsafe t+ in unsafeMkMText t data ParseEpAddressError = ParseEpAddressBadAddress ParseAddressError@@ -109,16 +112,19 @@ instance NFData ParseEpAddressError instance Buildable ParseEpAddressError where- build = \case- ParseEpAddressBadAddress err -> build err- ParseEpAddressRawBadAddress err -> build err+ build = buildRenderDoc++instance RenderDoc ParseEpAddressError where+ renderDoc context = \case+ ParseEpAddressBadAddress err -> renderDoc context err+ ParseEpAddressRawBadAddress err -> renderDoc context err ParseEpAddressBadEntryopint addr exception ->- "Invalid entrypoint given for raw adddress " <> hexF addr <>- " and failed with " <> build (show @Text exception)- ParseEpAddressBadRefAnn txt -> pretty $ "Invalid reference annotation: " <> txt- ParseEpAddressRefAnnError err -> build err+ "Invalid entrypoint given for raw adddress" <+> (renderAnyBuildable $ hexF addr)<>+ " and failed with" <+> (textStrict (show @Text exception))+ ParseEpAddressBadRefAnn txt -> "Invalid reference annotation:" <+> (textStrict txt)+ ParseEpAddressRefAnnError err -> renderDoc context err ParseEpAddressInvalidLength len ->- "Given raw entrypoint address has invalid length: " <> build len+ "Given raw entrypoint address has invalid length:" <+> int len -- | Parse an address which can be suffixed with entrypoint name -- (e.g. "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU%entrypoint").@@ -176,19 +182,19 @@ -- Following the Michelson specification, this type has the following invariants: -- 1. No entrypoint name is duplicated. -- 2. If @default@ entrypoint is explicitly assigned, no "arm" remains uncallable.-data ParamNotes (t :: T) = ParamNotesUnsafe+data ParamNotes (t :: T) = UnsafeParamNotes { pnNotes :: Notes t , pnRootAnn :: RootAnn } deriving stock (Show, Eq, Generic) deriving anyclass (NFData) pattern ParamNotes :: Notes t -> RootAnn -> ParamNotes t-pattern ParamNotes t f <- ParamNotesUnsafe t f+pattern ParamNotes t f <- UnsafeParamNotes t f {-# COMPLETE ParamNotes #-} -- | Parameter without annotations. starParamNotes :: SingI t => ParamNotes t-starParamNotes = ParamNotesUnsafe starNotes noAnn+starParamNotes = UnsafeParamNotes starNotes noAnn -- | Coordinates of "arm" in Or tree, used solely in error messages. type ArmCoords = [ArmCoord]@@ -198,10 +204,14 @@ instance NFData ArmCoord instance Buildable ArmCoord where- build = \case+ build = buildRenderDoc++instance RenderDoc ArmCoord where+ renderDoc _ = \case AcLeft -> "left" AcRight -> "right" + -- | Errors specific to parameter type declaration (entrypoints). data ParamEpError = ParamEpDuplicatedNames (NonEmpty EpName)@@ -211,20 +221,21 @@ instance NFData ParamEpError instance Buildable ParamEpError where- build = \case+ build = buildRenderDoc++instance RenderDoc ParamEpError where+ renderDoc context = \case ParamEpDuplicatedNames names -> mconcat [ "Duplicated entrypoint names: "- , mconcat . intersperse ", " $ map (surround "'" "'" . build) (toList names)+ , mconcat $ punctuate ", " . map (squotes . renderAnyBuildable) $ toList names ] ParamEpUncallableArm arm -> mconcat [ "Due to presence of 'default' entrypoint, one of contract \"arms\" \ \cannot be called: \""- , mconcat . intersperse " - " $ map build arm+ , mconcat . intersperse " - " $ map (renderDoc context) arm , "\"" , if length arm > 1 then " (in top-to-bottom order)" else "" ]- where- surround pre post builder = pre <> builder <> post -- | Check whether given notes are valid parameter notes. verifyParamNotes :: Notes t -> RootAnn -> Either ParamEpError ()@@ -295,7 +306,7 @@ -- | Construct 'ParamNotes' performing all necessary checks. mkParamNotes :: Notes t -> RootAnn -> Either ParamEpError (ParamNotes t)-mkParamNotes nt fa = verifyParamNotes nt fa $> ParamNotesUnsafe nt fa+mkParamNotes nt fa = verifyParamNotes nt fa $> UnsafeParamNotes nt fa ---------------------------------------------------------------------------- -- Entrypoint logic@@ -309,10 +320,10 @@ data EpLiftSequence (arg :: T) (param :: T) where EplArgHere :: EpLiftSequence arg arg EplWrapLeft- :: (KnownT subparam, KnownT r)+ :: (SingI subparam, SingI r) => EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr subparam r) EplWrapRight- :: (KnownT l, KnownT subparam)+ :: (SingI l, SingI subparam) => EpLiftSequence arg subparam -> EpLiftSequence arg ('TOr l subparam) deriving stock instance Eq (EpLiftSequence arg param)@@ -350,8 +361,8 @@ -- there is no explicit "default" one. -- -- Validity of such operation is not ensured.-epcCallRootUnsafe :: ParameterScope param => EntrypointCallT param param-epcCallRootUnsafe = EntrypointCall+unsafeEpcCallRoot :: ParameterScope param => EntrypointCallT param param+unsafeEpcCallRoot = EntrypointCall { epcName = DefEpName , epcParamProxy = Proxy , epcLiftSequence = EplArgHere@@ -362,7 +373,7 @@ :: forall p. (ParameterScope p, ForbidOr p) => EntrypointCallT p p-epcPrimitive = epcCallRootUnsafe+epcPrimitive = unsafeEpcCallRoot where _requireNoOr = Dict @(ForbidOr p) @@ -398,8 +409,8 @@ -- there is no explicit "default" one. -- -- Validity of such operation is not ensured.-sepcCallRootUnsafe :: ParameterScope param => SomeEntrypointCallT param-sepcCallRootUnsafe = SomeEpc epcCallRootUnsafe+unsafeSepcCallRoot :: ParameterScope param => SomeEntrypointCallT param+unsafeSepcCallRoot = SomeEpc unsafeEpcCallRoot -- | Call parameter which has no entrypoints, always safe. sepcPrimitive@@ -427,7 +438,9 @@ -> Maybe r withEpLiftSequence epName@(epNameToParamAnn -> epAnn) param cont = case (sing @param, param) of- (STOr lSing _, NTOr _ lFieldAnn rFieldAnn lNotes rNotes) ->+ (STOr lSing rSing, NTOr _ lFieldAnn rFieldAnn lNotes rNotes) ->+ withSingI lSing $+ withSingI rSing $ case (checkOpPresence lSing, checkNestedBigMapsPresence lSing) of (OpAbsent, NestedBigMapsAbsent) -> asum [ guard (lFieldAnn == epAnn) $> cont (lNotes, EplWrapLeft EplArgHere)@@ -484,4 +497,4 @@ -- | "Parameter" type of implicit account. tyImplicitAccountParam :: ParamNotes 'TUnit-tyImplicitAccountParam = ParamNotesUnsafe starNotes noAnn+tyImplicitAccountParam = UnsafeParamNotes starNotes noAnn
+ src/Michelson/Typed/Existential.hs view
@@ -0,0 +1,79 @@+-- SPDX-FileCopyrightText: 2021 Tocqueville Group+--+-- SPDX-License-Identifier: LicenseRef-MIT-TQ++module Michelson.Typed.Existential+ ( SomeConstant (..)+ , SomeConstrainedValue (..)+ , SomeContract (..)+ , SomeContractAndStorage (..)+ , SomeIsoValue (..)+ , SomeValue (..)+ , SomeStorage(..)+ ) where++import Fmt (Buildable(..))++import Michelson.Typed.Aliases+import Michelson.Typed.Convert ()+import Michelson.Typed.Haskell.Value (KnownIsoT)+import Michelson.Typed.Instr (Contract(..))+import Michelson.Typed.Scope+import Michelson.Typed.T (T(..))+import Util.Sing (eqParamSing)++data SomeConstrainedValue (c :: T -> Constraint) where+ SomeConstrainedValue+ :: forall (t :: T) (c :: T -> Constraint)+ . (c t)+ => Value t+ -> SomeConstrainedValue c++deriving stock instance Show (SomeConstrainedValue c)++-- TODO+-- @gromak: perhaps we should implement `SomeValue` in terms of+-- `SomeConstrainedValue`, but it will require changing quite a lot of code,+-- so it is postponed.++data SomeValue where+ SomeValue :: SingI t => Value t -> SomeValue++deriving stock instance Show SomeValue++instance Eq SomeValue where+ SomeValue v1 == SomeValue v2 = v1 `eqParamSing` v2++data SomeConstant where+ SomeConstant :: (ConstantScope t, SingI t) => Value t -> SomeConstant++instance Buildable SomeConstant where+ build (SomeConstant v) = build v++-- | Hides some Haskell value put in line with Michelson 'Value'.+data SomeIsoValue where+ SomeIsoValue :: (KnownIsoT a) => a -> SomeIsoValue++data SomeContract where+ SomeContract :: Contract cp st -> SomeContract++instance NFData SomeContract where+ rnf (SomeContract c) = rnf c++deriving stock instance Show SomeContract++-- | Represents a typed contract & a storage value of the type expected by the contract.+data SomeContractAndStorage where+ SomeContractAndStorage+ :: forall cp st.+ (StorageScope st, ParameterScope cp)+ => Contract cp st+ -> Value st+ -> SomeContractAndStorage++deriving stock instance Show SomeContractAndStorage++data SomeStorage where+ SomeStorage :: forall st. StorageScope st => Value st -> SomeStorage++deriving stock instance Show SomeStorage
src/Michelson/Typed/Extract.hs view
@@ -19,17 +19,17 @@ , pattern AsUTypeExt ) where -import Data.Singletons (Sing, SingI)+import Data.Singletons (Sing, SingI, fromSing, withSingI) import Michelson.Typed.Annotation (Notes(..), notesSing)-import Michelson.Typed.Sing (KnownT, SingT(..), fromSingT)+import Michelson.Typed.Sing (SingT(..)) import Michelson.Typed.T (T(..), toUType) import qualified Michelson.Untyped as Un {-# ANN module ("HLint: ignore Avoid lambda using `infix`" :: Text) #-} fromUType :: Un.Ty -> T-fromUType ut = withUType ut (fromSingT . notesSing)+fromUType ut = withUType ut (fromSing . notesSing) mkUType :: SingI x => Notes x -> Un.Ty mkUType notes = case (notesSing notes, notes) of@@ -49,28 +49,50 @@ (STUnit, NTUnit tn) -> Un.Ty Un.TUnit tn (STSignature, NTSignature tn) -> Un.Ty Un.TSignature tn (STChainId, NTChainId tn) -> Un.Ty Un.TChainId tn- (STOption _, NTOption tn n) -> Un.Ty (Un.TOption (mkUType n)) tn- (STList _, NTList tn n) -> Un.Ty (Un.TList (mkUType n)) tn- (STSet _, NTSet tn n) -> Un.Ty (Un.TSet (mkUType n)) tn+ (STOption t, NTOption tn n) -> Un.Ty (Un.TOption $ withSingI t $ mkUType n) tn+ (STList t, NTList tn n) -> Un.Ty (Un.TList $ withSingI t $ mkUType n) tn+ (STSet t, NTSet tn n) -> Un.Ty (Un.TSet $ withSingI t $ mkUType n) tn (STOperation, NTOperation tn) -> Un.Ty Un.TOperation tn (STNever, NTNever tn) -> Un.Ty Un.TNever tn- (STContract _, NTContract tn n) ->- Un.Ty (Un.TContract (mkUType n)) tn- (STPair _ _, NTPair tn fl fr vl vr nl nr) ->- Un.Ty (Un.TPair fl fr vl vr (mkUType nl) (mkUType nr)) tn- (STOr _ _, NTOr tn fl fr nl nr) ->- Un.Ty (Un.TOr fl fr (mkUType nl) (mkUType nr)) tn- (STLambda _ _, NTLambda tn np nq) ->- Un.Ty (Un.TLambda (mkUType np) (mkUType nq)) tn- (STMap _ _, NTMap tn nk nv) ->- Un.Ty (Un.TMap (mkUType nk) (mkUType nv)) tn- (STBigMap _ _, NTBigMap tn nk nv) ->- Un.Ty (Un.TBigMap (mkUType nk) (mkUType nv)) tn+ (STContract t, NTContract tn n) ->+ Un.Ty (Un.TContract $ withSingI t (mkUType n)) tn+ (STTicket t, NTTicket tn n) ->+ Un.Ty (Un.TTicket $ withSingI t (mkUType n)) tn+ (STPair t t', NTPair tn fl fr vl vr nl nr) ->+ Un.Ty+ (Un.TPair fl fr vl vr+ (withSingI t $ mkUType nl)+ (withSingI t' $ mkUType nr))+ tn+ (STOr t t', NTOr tn fl fr nl nr) ->+ Un.Ty+ (Un.TOr fl fr+ (withSingI t $ mkUType nl)+ (withSingI t' $ mkUType nr))+ tn+ (STLambda t t', NTLambda tn np nq) ->+ Un.Ty+ (Un.TLambda+ (withSingI t $ mkUType np)+ (withSingI t' $ mkUType nq))+ tn+ (STMap t t', NTMap tn nk nv) ->+ Un.Ty+ (Un.TMap+ (withSingI t $ mkUType nk)+ (withSingI t' $ mkUType nv))+ tn+ (STBigMap t t', NTBigMap tn nk nv) ->+ Un.Ty+ (Un.TBigMap+ (withSingI t $ mkUType nk)+ (withSingI t' $ mkUType nv))+ tn -- | Convert 'Un.Ty' to the isomorphic set of information from typed world. withUType :: Un.Ty- -> (forall t. KnownT t => Notes t -> r)+ -> (forall t. SingI t => Notes t -> r) -> r withUType (Un.Ty ut tn) cont = case ut of @@ -144,6 +166,10 @@ \(notesContractT :: Notes contractT) -> cont (NTContract tn notesContractT) + Un.TTicket ticketT -> withUType ticketT $+ \(notesTicketT :: Notes ticketT) ->+ cont (NTTicket tn notesTicketT)+ Un.TPair la ra lv rv lt rt -> withUType lt $ \ln -> withUType rt $ \rn ->@@ -170,7 +196,7 @@ cont @('TBigMap _ _) (NTBigMap tn keyN valN) -- Helper datatype for 'AsUType'.-data SomeTypedInfo = forall t. KnownT t => SomeTypedInfo (Notes t)+data SomeTypedInfo = forall t. SingI t => SomeTypedInfo (Notes t) -- | Transparently represent untyped 'Ty' as wrapper over @Notes t@ -- from typed world with @SingI t@ constraint.@@ -181,13 +207,13 @@ -- Note about constraints: pattern signatures usually require two constraints - -- one they require and another one which they provide. In our case we require -- nothing (thus first constraint is @()@) and provide some knowledge about @t@.-pattern AsUType :: () => (KnownT t) => Notes t -> Un.Ty+pattern AsUType :: () => (SingI t) => Notes t -> Un.Ty pattern AsUType notes <- ((\ut -> withUType ut SomeTypedInfo) -> SomeTypedInfo notes) where AsUType notes = mkUType notes {-# COMPLETE AsUType #-} -- | Similar to 'AsUType', but also gives 'Sing' for given type.-pattern AsUTypeExt :: () => (KnownT t) => Sing t -> Notes t -> Un.Ty+pattern AsUTypeExt :: () => (SingI t) => Sing t -> Notes t -> Un.Ty pattern AsUTypeExt sng notes <- AsUType notes@(notesSing -> sng) where AsUTypeExt _ notes = AsUType notes {-# COMPLETE AsUTypeExt #-}
src/Michelson/Typed/Haskell/Doc.hs view
@@ -29,13 +29,13 @@ , poly2TypeDocMdReference , homomorphicTypeDocHaskellRep , concreteTypeDocHaskellRep- , concreteTypeDocHaskellRepUnsafe+ , unsafeConcreteTypeDocHaskellRep , haskellAddNewtypeField , haskellRepNoFields , haskellRepStripFieldPrefix , homomorphicTypeDocMichelsonRep , concreteTypeDocMichelsonRep- , concreteTypeDocMichelsonRepUnsafe+ , unsafeConcreteTypeDocMichelsonRep , DType (..) , DStorageType (..)@@ -253,7 +253,7 @@ -- For polymorhpic types consider using 'concreteTypeDocMichelsonRep' as implementation. typeDocMichelsonRep :: TypeDocMichelsonRep a default typeDocMichelsonRep- :: (SingI (ToT a), IsHomomorphic a)+ :: (KnownIsoT a, IsHomomorphic a) => TypeDocMichelsonRep a typeDocMichelsonRep = homomorphicTypeDocMichelsonRep @@ -512,17 +512,17 @@ , HaveCommonTypeCtor b a ) => TypeDocHaskellRep b-concreteTypeDocHaskellRep = concreteTypeDocHaskellRepUnsafe @a+concreteTypeDocHaskellRep = unsafeConcreteTypeDocHaskellRep @a -- | Version of 'concreteTypeDocHaskellRep' which does not ensure -- whether the type for which representation is built is any similar to -- the original type which you implement a 'TypeHasDoc' instance for.-concreteTypeDocHaskellRepUnsafe+unsafeConcreteTypeDocHaskellRep :: forall a b. ( Typeable a, GenericIsoValue a, GTypeHasDoc (G.Rep a) ) => TypeDocHaskellRep b-concreteTypeDocHaskellRepUnsafe _ descr = Just+unsafeConcreteTypeDocHaskellRep _ descr = Just ( Just (DocTypeRepLHS . toText . showtype $ Proxy @a) , gTypeDocHaskellRep @(G.Rep a) descr )@@ -567,7 +567,7 @@ -- | Implement 'typeDocMichelsonRep' for homomorphic type. homomorphicTypeDocMichelsonRep :: forall a.- SingI (ToT a)+ KnownIsoT a => TypeDocMichelsonRep a homomorphicTypeDocMichelsonRep _ = ( Nothing@@ -579,21 +579,21 @@ -- This function exists for the same reason as 'concreteTypeDocHaskellRep'. concreteTypeDocMichelsonRep :: forall a b.- (Typeable a, SingI (ToT a), HaveCommonTypeCtor b a)+ (Typeable a, KnownIsoT a, HaveCommonTypeCtor b a) => TypeDocMichelsonRep b concreteTypeDocMichelsonRep _ = ( Just (DocTypeRepLHS . toText . showtype $ Proxy @a) , demote @(ToT a) ) --- | Version of 'concreteTypeDocHaskellRepUnsafe' which does not ensure+-- | Version of 'unsafeConcreteTypeDocHaskellRep' which does not ensure -- whether the type for which representation is built is any similar to -- the original type which you implement a 'TypeHasDoc' instance for.-concreteTypeDocMichelsonRepUnsafe+unsafeConcreteTypeDocMichelsonRep :: forall a b.- (Typeable a, SingI (ToT a))+ (Typeable a, KnownIsoT a) => TypeDocMichelsonRep b-concreteTypeDocMichelsonRepUnsafe _ =+unsafeConcreteTypeDocMichelsonRep _ = ( Just (DocTypeRepLHS . toText . showtype $ Proxy @a) , demote @(ToT a) )@@ -812,10 +812,18 @@ typeDocName _ = "Contract" typeDocMdReference = poly1TypeDocMdReference typeDocMdDescription = "Contract primitive with given type of parameter."- typeDocDependencies _ = [dTypeDep @cp]+ typeDocDependencies _ = [dTypeDep @cp, dTypeDep @Integer] typeDocHaskellRep _ _ = Nothing typeDocMichelsonRep = concreteTypeDocMichelsonRep @(ContractRef Integer) +instance PolyTypeHasDocC '[a] => TypeHasDoc (Ticket a) where+ typeDocName _ = "Ticket"+ typeDocMdReference = poly1TypeDocMdReference+ typeDocMdDescription = "Ticket primitive."+ typeDocDependencies _ = [dTypeDep @a, dTypeDep @MText]+ typeDocHaskellRep _ _ = Nothing+ typeDocMichelsonRep = concreteTypeDocMichelsonRep @(Ticket MText)+ instance (PolyCTypeHasDocC '[k], PolyTypeHasDocC '[v], Ord k) => TypeHasDoc (Map k v) where typeDocName _ = "Map"@@ -914,7 +922,7 @@ instance ( TypeHasDoc (ApplyNamedFunctor f a) , KnownSymbol n- , SingI (ToT (ApplyNamedFunctor f Integer))+ , KnownIsoT (ApplyNamedFunctor f Integer) , Typeable f, Typeable a ) => TypeHasDoc (NamedF f a n) where
src/Michelson/Typed/Haskell/Instr/Product.hs view
@@ -10,7 +10,7 @@ ( InstrGetFieldC , InstrSetFieldC , InstrConstructC- , instrGetField+ , instrToField , instrSetField , instrConstruct , instrConstructStack@@ -110,12 +110,12 @@ ---------------------------------------------------------------------------- -- | Make an instruction which accesses given field of the given datatype.-instrGetField+instrToField :: forall dt name st. InstrGetFieldC dt name => Label name -> Instr (ToT dt ': st) (ToT (GetFieldType dt name) ': st)-instrGetField _ =- gInstrGetField @name @(G.Rep dt) @(LnrBranch (GetNamed name dt))+instrToField _ =+ gInstrToField @name @(G.Rep dt) @(LnrBranch (GetNamed name dt)) @(GetFieldType dt name) -- | Constraint for 'instrGetField'.@@ -126,7 +126,7 @@ (LnrFieldType (GetNamed name dt)) ) -{- Note about bulkiness of `instrGetField` type signature:+{- Note about bulkiness of `instrToField` type signature: Read this only if you are going to modify the signature qualitatively. @@ -145,22 +145,22 @@ (x :: Type -> Type) (path :: Path) (fieldTy :: Type) where- gInstrGetField+ gInstrToField :: GIsoValue x => Instr (GValueType x ': s) (ToT fieldTy ': s) instance GInstrGet name x path f => GInstrGet name (G.M1 t i x) path f where- gInstrGetField = gInstrGetField @name @x @path @f+ gInstrToField = gInstrToField @name @x @path @f instance (IsoValue f, ToT f ~ ToT f') => GInstrGet name (G.Rec0 f) '[] f' where- gInstrGetField = Nop+ gInstrToField = Nop instance (GInstrGet name x path f, GIsoValue y) => GInstrGet name (x :*: y) ('L ': path) f where- gInstrGetField = CAR `Seq` gInstrGetField @name @x @path @f+ gInstrToField = CAR `Seq` gInstrToField @name @x @path @f instance (GInstrGet name y path f, GIsoValue x) => GInstrGet name (x :*: y) ('R ': path) f where- gInstrGetField = CDR `Seq` gInstrGetField @name @y @path @f+ gInstrToField = CDR `Seq` gInstrToField @name @y @path @f -- Examples ----------------------------------------------------------------------------@@ -168,10 +168,10 @@ type MyType1 = ("int" :! Integer, "bytes" :! ByteString, "bytes2" :? ByteString) _getIntInstr1 :: Instr (ToT MyType1 ': s) (ToT Integer ': s)-_getIntInstr1 = instrGetField @MyType1 #int+_getIntInstr1 = instrToField @MyType1 #int _getTextInstr1 :: Instr (ToT MyType1 ': s) (ToT (Maybe ByteString) ': s)-_getTextInstr1 = instrGetField @MyType1 #bytes2+_getTextInstr1 = instrToField @MyType1 #bytes2 data MyType2 = MyType2 { getInt :: Integer@@ -182,11 +182,11 @@ deriving anyclass (IsoValue) _getIntInstr2 :: Instr (ToT MyType2 ': s) (ToT () ': s)-_getIntInstr2 = instrGetField @MyType2 #getUnit+_getIntInstr2 = instrToField @MyType2 #getUnit _getIntInstr2' :: Instr (ToT MyType2 ': s) (ToT Integer ': s) _getIntInstr2' =- instrGetField @MyType2 #getMyType1 `Seq` instrGetField @MyType1 #int+ instrToField @MyType2 #getMyType1 `Seq` instrToField @MyType1 #int ---------------------------------------------------------------------------- -- Value modification instruction@@ -228,13 +228,13 @@ instance (GInstrSetField name x path f, GIsoValue y) => GInstrSetField name (x :*: y) ('L ': path) f where gInstrSetField =- DIP (DUP `Seq` DIP CDR `Seq` CAR) `Seq`+ DIP UNPAIR `Seq` gInstrSetField @name @x @path @f `Seq` PAIR instance (GInstrSetField name y path f, GIsoValue x) => GInstrSetField name (x :*: y) ('R ': path) f where gInstrSetField =- DIP (DUP `Seq` DIP CAR `Seq` CDR) `Seq`+ DIP (UNPAIR `Seq` SWAP) `Seq` gInstrSetField @name @y @path @f `Seq` SWAP `Seq` PAIR
src/Michelson/Typed/Haskell/Instr/Sum.hs view
@@ -15,7 +15,7 @@ , hsWrap , instrCase , (//->)- , instrUnwrapUnsafe+ , unsafeInstrUnwrap , hsUnwrap , CaseClauseParam (..)@@ -617,14 +617,14 @@ -- Rules which apply to 'instrWrap' function work here as well. -- Although, unlike @instrWrap@, this function does not work for nullary -- constructors.-instrUnwrapUnsafe+unsafeInstrUnwrap :: forall dt name st. InstrUnwrapC dt name => Label name -> Instr (ToT dt ': st) (ToT (CtorOnlyField name dt) ': st)-instrUnwrapUnsafe _ =- gInstrUnwrapUnsafe @(G.Rep dt) @(LnrBranch (GetNamed name dt))+unsafeInstrUnwrap _ =+ unsafeGInstrUnwrap @(G.Rep dt) @(LnrBranch (GetNamed name dt)) @(CtorOnlyField name dt) type InstrUnwrapC dt name =@@ -651,33 +651,33 @@ (x :: Type -> Type) (path :: Path) (entryTy :: Type) where- gInstrUnwrapUnsafe+ unsafeGInstrUnwrap :: GIsoValue x => Instr (GValueType x ': s) (ToT entryTy ': s) gHsUnwrap :: x p -> Maybe entryTy instance GInstrUnwrap x path e => GInstrUnwrap (G.D1 i x) path e where- gInstrUnwrapUnsafe = gInstrUnwrapUnsafe @x @path @e+ unsafeGInstrUnwrap = unsafeGInstrUnwrap @x @path @e gHsUnwrap = gHsUnwrap @x @path @e . G.unM1 instance (GInstrUnwrap x path e, GIsoValue y, SingI (GValueType y)) => GInstrUnwrap (x :+: y) ('L ': path) e where- gInstrUnwrapUnsafe = IF_LEFT (gInstrUnwrapUnsafe @x @path @e) failWithWrongCtor+ unsafeGInstrUnwrap = IF_LEFT (unsafeGInstrUnwrap @x @path @e) failWithWrongCtor gHsUnwrap = \case G.L1 x -> gHsUnwrap @x @path @e x G.R1 _ -> Nothing instance (GInstrUnwrap y path e, GIsoValue x, SingI (GValueType x)) => GInstrUnwrap (x :+: y) ('R ': path) e where- gInstrUnwrapUnsafe = IF_LEFT failWithWrongCtor (gInstrUnwrapUnsafe @y @path @e)+ unsafeGInstrUnwrap = IF_LEFT failWithWrongCtor (unsafeGInstrUnwrap @y @path @e) gHsUnwrap = \case G.R1 y -> gHsUnwrap @y @path @e y G.L1 _ -> Nothing instance (IsoValue e) => GInstrUnwrap (G.C1 c (G.S1 i (G.Rec0 e))) '[ 'S] e where- gInstrUnwrapUnsafe = Nop+ unsafeGInstrUnwrap = Nop gHsUnwrap = Just . G.unK1 . G.unM1 . G.unM1 -- This is the case when a sum type is part of another sum type.@@ -688,7 +688,7 @@ , GIsoValue (G.Rep sub) ) => GInstrUnwrap (G.C1 c (G.S1 i (G.Rec0 sub))) ('S ': x ': xs) e where- gInstrUnwrapUnsafe = gInstrUnwrapUnsafe @(G.Rep sub) @path @e+ unsafeGInstrUnwrap = unsafeGInstrUnwrap @(G.Rep sub) @path @e gHsUnwrap = gHsUnwrap @(G.Rep sub) @path @e . G.from . G.unK1 . G.unM1 . G.unM1 -- | Failure indicating that we expected value created with one constructor,@@ -704,16 +704,16 @@ ---------------------------------------------------------------------------- _unwrapMyType :: Instr (ToT MyType ': s) (ToT Integer ': s)-_unwrapMyType = instrUnwrapUnsafe @MyType #cMyCtor+_unwrapMyType = unsafeInstrUnwrap @MyType #cMyCtor _unwrapMyCompoundType :: Instr (ToT MyCompoundType ': s) (ToT Integer ': s)-_unwrapMyCompoundType = instrUnwrapUnsafe @MyCompoundType #cMyCtor+_unwrapMyCompoundType = unsafeInstrUnwrap @MyCompoundType #cMyCtor _unwrapMyCompoundType2 :: Instr (ToT MyCompoundType ': s) (ToT Address ': s)-_unwrapMyCompoundType2 = instrUnwrapUnsafe @MyCompoundType #cCompoundPart3+_unwrapMyCompoundType2 = unsafeInstrUnwrap @MyCompoundType #cCompoundPart3 _unwrapMyCompoundType3 :: Instr (ToT MyCompoundType ': s) (ToT Bool ': s)-_unwrapMyCompoundType3 = instrUnwrapUnsafe @MyCompoundType #cWrapBool+_unwrapMyCompoundType3 = unsafeInstrUnwrap @MyCompoundType #cWrapBool _unwrapMyCompoundType4 :: Instr (ToT MyCompoundType ': s) (ToT MyType' ': s)-_unwrapMyCompoundType4 = instrUnwrapUnsafe @MyCompoundType #cCompoundPart4+_unwrapMyCompoundType4 = unsafeInstrUnwrap @MyCompoundType #cCompoundPart4
src/Michelson/Typed/Haskell/LooseSum.hs view
@@ -19,14 +19,15 @@ , LooseSumC ) where -import Data.Typeable (TypeRep, cast, typeRep)+import Data.Singletons import GHC.Generics ((:*:), (:+:)) import qualified GHC.Generics as G import Michelson.Typed.Aliases+import Michelson.Typed.Existential import Michelson.Typed.Haskell.Value import Michelson.Typed.T-import Michelson.Typed.Value+import Util.Sing (castSing) import Util.TypeLits -- | Possible outcomes of an attempt to construct a Haskell ADT value@@ -36,7 +37,7 @@ -- ^ Composed fine. | ComposeCtorNotFound -- ^ No constructor with such name.- | ComposeFieldTypeMismatch TypeRep TypeRep+ | ComposeFieldTypeMismatch T T -- ^ Found required constructor, but type of data does not correspond -- to provided one. deriving stock (Functor)@@ -104,7 +105,7 @@ gExtractField = gExtractField . G.unM1 gMakeField v = G.M1 <$> gMakeField @x v -instance (Typeable a, IsoValue a) =>+instance IsoValue a => GAccessField (G.Rec0 a) where gExtractField = SomeValue . toVal . G.unK1 gMakeField (SomeValue v) = G.K1 . fromVal <$> composeCast v@@ -113,10 +114,10 @@ gExtractField G.U1 = SomeValue $ toVal () gMakeField (SomeValue v) = G.U1 <$ composeCast @_ @'TUnit v -composeCast :: forall a b. (Typeable a, Typeable b) => Value a -> ComposeResult (Value b)+composeCast :: forall a b. (SingI a, SingI b) => Value a -> ComposeResult (Value b) composeCast a =- case cast a of- Nothing -> ComposeFieldTypeMismatch (typeRep (Proxy @a)) (typeRep (Proxy @b))+ case castSing a of+ Nothing -> ComposeFieldTypeMismatch (demote @a) (demote @b) Just b -> ComposeOk b instance
src/Michelson/Typed/Haskell/Value.hs view
@@ -9,15 +9,13 @@ ( -- * Value conversions IsoValue (..) , KnownIsoT- , KnownT , GIsoValue (GValueType) , ToT'- , SomeIsoValue (..)- , AnyIsoValue (..) , GenericIsoValue , WellTyped , WellTypedIsoValue , WellTypedToT+ , HasNoOpToT , Dict(..) -- * Re-exporting to use in tests. @@ -27,7 +25,10 @@ , ContractRef (..) , coerceContractRef , contractRefToAddr- , BigMap (..)+ , Ticket (..)+ , BigMapId(..)+ , BigMap(..)+ , mkBigMap -- * Stack conversion , ToTs@@ -37,13 +38,15 @@ , totsAppendLemma ) where -import Data.Constraint (Dict(..), (:-)(..))+import Data.Constraint (Dict(..))+import Data.Data (Data) import Data.Default (Default(..))+import Data.Foldable (Foldable(foldr)) import qualified Data.Map.Strict as Map import qualified Data.Set as Set import Data.Vinyl.Core (Rec(..)) import Fmt (Buildable(..), mapF)-import GHC.Exts (IsList)+import GHC.Exts as Exts (IsList(..)) import GHC.Generics ((:*:)(..), (:+:)(..)) import qualified GHC.Generics as G import Named (NamedF(..))@@ -51,7 +54,7 @@ import Michelson.Text import Michelson.Typed.Aliases import Michelson.Typed.Entrypoints-import Michelson.Typed.Sing+import Michelson.Typed.Scope import Michelson.Typed.T import Michelson.Typed.Value import Tezos.Address (Address)@@ -63,7 +66,7 @@ -- Complex values isomorphism ---------------------------------------------------------------------------- -type KnownIsoT a = KnownT (ToT a)+type KnownIsoT a = SingI (ToT a) -- | Isomorphism between Michelson values and plain Haskell types. --@@ -93,13 +96,6 @@ ToT' (t :: T) = t ToT' (t :: Type) = ToT t --- | Hides some Haskell value put in line with Michelson 'Value'.-data SomeIsoValue where- SomeIsoValue :: (KnownIsoT a) => a -> SomeIsoValue---- | Any Haskell value which can be converted to Michelson 'Value'.-newtype AnyIsoValue = AnyIsoValue (forall a. IsoValue a => a)- -- Instances ---------------------------------------------------------------------------- @@ -252,6 +248,9 @@ type WellTypedToT a = WellTyped (ToT a) type WellTypedIsoValue a = (WellTyped (ToT a), IsoValue a) +type HasNoOpToT a = HasNoOp (ToT a)+type HasNoBigMapToT a = HasNoBigMap (ToT a)+ -- | Since @Contract@ name is used to designate contract code, lets call -- analogy of 'TContract' type as follows. --@@ -264,10 +263,10 @@ , crEntrypoint :: SomeEntrypointCall arg } deriving stock (Eq, Show) -instance (WellTypedToT arg) => Buildable (ContractRef arg) where+instance (IsoValue (ContractRef arg)) => Buildable (ContractRef arg) where build = buildVContract . toVal -instance (WellTypedToT arg) => IsoValue (ContractRef arg) where+instance (HasNoOpToT arg, WellTypedToT arg) => IsoValue (ContractRef arg) where type ToT (ContractRef arg) = 'TContract (ToT arg) toVal ContractRef{..} = VContract crAddress crEntrypoint fromVal (VContract addr epc) = ContractRef addr epc@@ -279,20 +278,71 @@ contractRefToAddr :: ContractRef cp -> EpAddress contractRefToAddr ContractRef{..} = EpAddress crAddress (sepcName crEntrypoint) -newtype BigMap k v = BigMap { unBigMap :: Map k v }- deriving stock (Eq, Show)- deriving newtype (Default, Semigroup, Monoid, One, Container, IsList)+-- | Ticket type.+data Ticket (arg :: Type) = Ticket+ { tTicketer :: Address+ , tData :: arg+ , tAmount :: Natural+ } deriving stock (Eq, Show) +instance (Comparable (ToT a), IsoValue a) => IsoValue (Ticket a) where+ type ToT (Ticket a) = 'TTicket (ToT a)+ toVal Ticket{..} = VTicket tTicketer (toVal tData) tAmount+ fromVal (VTicket tTicketer dat tAmount) = Ticket{ tData = fromVal dat, .. }++-- | Phantom type that represents the ID of a big_map with+-- keys of type @k@ and values of type @v@.+newtype BigMapId k v = BigMapId { unBigMapId :: Natural }+ -- Note: we purposefully do not derive an `Eq` instance.+ -- If we did, it would be possible for a @cleveland@ user to mistakenly+ -- compare two big_map IDs, whilst being under the impression that they were+ -- actually comparing the big_map's contents.+ -- To avoid this confusion, we simply do not create an `Eq` instance.+ -- For context, see: https://gitlab.com/morley-framework/morley/-/merge_requests/833#note_598577341+ deriving stock (Show, Data)+ deriving newtype (IsoValue, Buildable, Num)++data BigMap k v = BigMap+ { bmId :: Maybe (BigMapId k v)+ , bmMap :: Map k v+ }+ deriving stock (Show, Generic, Data)+ deriving anyclass (Default, Container)++mkBigMap :: Ord k => [(k, v)] -> BigMap k v+mkBigMap = Exts.fromList++instance Ord k => Semigroup (BigMap k v) where+ BigMap _ m1 <> BigMap _ m2 = BigMap Nothing (m1 <> m2)++instance Foldable (BigMap k) where+ foldr f z (BigMap _ bmMap) = Map.foldr f z bmMap++instance One (BigMap k v) where+ type OneItem (BigMap k v) = OneItem (Map k v)+ one x = BigMap Nothing (one x)++instance Ord k => IsList (BigMap k v) where+ type Item (BigMap k v) = Item (Map k v)+ fromList xs = BigMap Nothing (Exts.fromList xs)+ toList (BigMap _ xs) = Exts.toList xs+ instance (Ord k, Buildable k, Buildable v) => Buildable (BigMap k v) where build = mapF instance- ( WellTypedToT k, WellTypedToT v, Comparable (ToT k)- , Ord k, IsoValue k, IsoValue v+ ( Comparable (ToT k) , Ord k, IsoValue k+ , IsoValue v, HasNoBigMapToT v, HasNoOpToT v ) => IsoValue (BigMap k v) where type ToT (BigMap k v) = 'TBigMap (ToT k) (ToT v)- toVal = VBigMap . Map.mapKeys toVal . Map.map toVal . unBigMap- fromVal (VBigMap x) = BigMap $ Map.map fromVal $ Map.mapKeys fromVal x+ toVal (BigMap bmId bmMap) =+ VBigMap+ (unBigMapId <$> bmId)+ (Map.mapKeys toVal $ Map.map toVal bmMap)+ fromVal (VBigMap bmId x) =+ BigMap+ (BigMapId <$> bmId)+ (Map.map fromVal $ Map.mapKeys fromVal x) -- Generic magic ----------------------------------------------------------------------------@@ -308,7 +358,7 @@ -- -- In case an unbalanced tree is needed, the Generic instance can be derived by -- using the utilities in the 'Util.Generics' module.-class KnownT (GValueType x) =>+class SingI (GValueType x) => GIsoValue (x :: Type -> Type) where type GValueType x :: T gToValue :: x p -> Value (GValueType x)@@ -401,7 +451,7 @@ -- 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, WellTypedSuperC t) => WellTyped (t :: T) where+class (SingI t, WellTypedSuperC t) => WellTyped (t :: T) where -- | Constraints required for instance of a given type. type WellTypedSuperC t :: Constraint type WellTypedSuperC _ = ()@@ -418,8 +468,10 @@ 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- type WellTypedSuperC ('TContract t) = WellTyped t+instance (WellTyped t, HasNoOp t) => WellTyped ('TContract t) where+ type WellTypedSuperC ('TContract t) = (WellTyped t, HasNoOp t)+instance (WellTyped t, Comparable t) => WellTyped ('TTicket t) where+ type WellTypedSuperC ('TTicket t) = (WellTyped t, Comparable 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@@ -428,8 +480,10 @@ 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 (Comparable k, WellTyped k, WellTyped v, HasNoBigMap v, HasNoOp v)+ => WellTyped ('TBigMap k v) where+ type WellTypedSuperC ('TBigMap k v) = ( Comparable k, WellTyped k, WellTyped v+ , HasNoBigMap v, HasNoOp v) instance WellTyped 'TInt instance WellTyped 'TNat instance WellTyped 'TString
src/Michelson/Typed/Instr.hs view
@@ -7,6 +7,8 @@ -- | Module, containing data types for Michelson value. module Michelson.Typed.Instr ( Instr (..)+ , castInstr+ , pattern (:#) , ExtInstr (..) , CommentType (..) , StackRef (..)@@ -45,6 +47,7 @@ import Data.Default import Data.Singletons (Sing)+import Data.Type.Equality ((:~:)(..)) import Data.Vinyl (RMap, Rec(..), RecordToList, ReifyConstraint(..)) import Fmt ((+||), (||+)) import GHC.TypeNats (type (+))@@ -58,19 +61,125 @@ import Michelson.Typed.Entrypoints import Michelson.Typed.Polymorphic import Michelson.Typed.Scope-import Michelson.Typed.Sing (KnownT) import Michelson.Typed.T (T(..)) import Michelson.Typed.TypeLevel (CombedPairLeafCount, CombedPairLeafCountIsAtLeast, CombedPairNodeCount, CombedPairNodeIndexIsValid, IsPair) import Michelson.Typed.Value (Comparable, ContractInp, ContractOut, Value'(..)) import Michelson.Untyped- (Annotation(..), EntriesOrder(..), FieldAnn, TypeAnn, VarAnn, VarAnns, entriesOrderToInt)+ (Annotation(..), EntriesOrder(..), FieldAnn, StackFn, StackTypePattern, TypeAnn, VarAnn, VarAnns,+ entriesOrderToInt) import Util.Peano+import Util.PeanoNatural+import Util.Sing (eqI) import Util.TH import Util.Type (If, KnownList, type (++)) import Util.TypeLits (ErrorMessage(ShowType, Text, (:$$:), (:<>:)), TypeErrorUnless) +{-+Note [Annotations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++When typechecking a sequence of instructions:++1. We'll typecheck an "untyped instruction" like `EMPTY_SET :ta @va unit`, producing:+ * a "typed instruction" `EMPTY_SET :: Instr s (TSet TUnit : s)`, and+ * an output stack with a `@va set :ta int` at the top.+2. In `Michelson.TypeCheck.Helpers.wrapWithNotes`:+ * if the original instruction had a var annotation (e.g. `SOME_INSTR @some_ann`),+ then we wrap the "typed instruction" in `InstrWithVarNotes`.+ * if the element at the top of the output stack has a var annotation,+ we wrap it in `InstrWithVarAnns`.+ * if the element at the top of the output stack has field/type anns,+ we wrap it in `InstrWithNotes`+ ```+ InstrWithNotes Proxy (NTSet "ta" (NTUnit "")) $+ InstrWithVarNotes (one "va") $+ InstrWithVarAnns (OneVarAnn "va") $+ EMPTY_SET+ ```++These "meta-instruction" wrappers are later used in the interpreter/serializer.++The interpreter ('Michelson.Interpret'):+ * Looks at the typed instruction (e.g. `EMPTY_SET`), and simply adds/removes/moves elements+ in the stack, without caring about annotations.+ * Looks at the `InstrWithNotes` and `InstrWithVarAnns` meta-instructions, and blindly+ applies a series of annotations to the output stack, without caring about the underlying+ instruction.++The serializer ('Michelson.Interpret.Pack'):+ * Looks at the `InstrWithNotes` and `InstrWithVarNotes` meta-instructions, and infers+ that the original `EMPTY_SET` instruction must have had two explicit `:ta` and `@va` annotations.++Notice that the interpreter does not care about the `InstrWithVarNotes` meta-instruction, and+the serializer does not care about the `InstrWithVarAnns` meta-instruction.++++Note [Annotations - Exceptional scenarios]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++For the most part, this works without a hitch.+However, `wrapWithNotes` makes the assumption that we can infer an instruction's+original annotations by simply looking at the output stack, e.g.:++> If after running an `EMPTY_SET` instruction we end up with a `@va set :ta int`+> at the top of output stack, then we can infer that the `EMPTY_SET` instruction+> had two `@va` and `:ta` annotations.++Unfortunately, that assumption doesn't always hold.+Here are some counter examples:++* Special annotations.+ These 3 `CAR` instructions will all put a `@p.a nat` at the top of the stack:++ > PUSH @p (pair (nat %a) nat) (Pair 1 2);+ > CAR @%%;++ > PUSH (pair (nat %p.a) nat) (Pair 1 2);+ > CAR @%;++ > PUSH (pair (nat %p.a) nat) (Pair 1 2);+ > CAR @p.a;++ Therefore, it's impossible for `wrapWithNotes` to figure out what+ CAR's original var annotation was.++ This scenario affects all instructions that can take special annotations:+ - PAIR, LEFT, RIGHT: accept special field anns+ - UNPAIR, CAR, CDR: accept special var anns++* Annotations that do not affect the output stack whatsoever.+ For example, CAR may take a field annotation, but it's only used by the typechecker+ to verify that the pair in the input stack has a matching field ann.++ The following instructions will generate the exact same output stack,+ with an un-annotated `nat` at the top.++ > PUSH (pair (nat %a) nat) (Pair 1 2);+ > CAR %a;++ > PUSH (pair (nat %a) nat) (Pair 1 2);+ > CAR;++ Therefore, it's impossible for `wrapWithNotes` to figure out whether+ CAR had a field annotation.++ This scenario affects: UNPAIR, CAR, CDR.+++In situations like the above, where the instruction's annotations cannot be inferred from+looking at the output stack, we have to save and store the instruction's annotations inside+the typed instruction's constructor, instead of using meta-instructions.+E.g.:++> AnnCAR :: VarAnn -> FieldAnn -> Instr ('TPair a b ': s) (a ': s)++TODO [#580]: address the assumptions mentioned above.++-}+ -- This next comment is needed to run the doctest examples throughout this module. -- $setup@@ -80,7 +189,7 @@ -- | Constraint that is used in DUPN, we want to share it with -- typechecking code and eDSL code. type ConstraintDUPN' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) =- ( SingI n, KnownPeano n, RequireLongerOrSameLength inp n, n > 'Z ~ 'True+ ( RequireLongerOrSameLength inp n, n > 'Z ~ 'True , inp ~ (Take (Decrement n) inp ++ (a ': Drop n inp)) , out ~ (a ': inp) )@@ -91,7 +200,7 @@ -- typechecking code and eDSL code. type ConstraintDIPN' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (s :: [kind]) (s' :: [kind]) =- ( SingI n, KnownPeano n, RequireLongerOrSameLength inp n+ ( RequireLongerOrSameLength inp n , ((Take n inp) ++ s) ~ inp , ((Take n inp) ++ s') ~ out )@@ -102,7 +211,7 @@ -- typechecking code and eDSL code. type ConstraintDIG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) =- ( SingI n, KnownPeano n, RequireLongerThan inp n+ ( RequireLongerThan inp n , inp ~ (Take n inp ++ (a ': Drop ('S n) inp)) , out ~ (a ': Take n inp ++ Drop ('S n) inp) )@@ -113,7 +222,7 @@ -- typechecking code and eDSL code. type ConstraintDUG' kind (n :: Peano) (inp :: [kind]) (out :: [kind]) (a :: kind) =- ( SingI n, KnownPeano n, RequireLongerThan out n+ ( RequireLongerThan out n , inp ~ (a ': Drop ('S 'Z) inp) , out ~ (Take n (Drop ('S 'Z) inp) ++ (a ': Drop ('S n) inp)) )@@ -123,8 +232,6 @@ type ConstraintPairN (n :: Peano) (inp :: [T]) = ( RequireLongerOrSameLength inp n , TypeErrorUnless (n >= ToPeano 2) ('Text "'PAIR n' expects n ≥ 2")- , SingI n- , KnownPeano n ) type PairN (n :: Peano) (s :: [T]) = (RightComb (Take n s) ': Drop n s)@@ -156,8 +263,6 @@ ':<>: 'ShowType pair ) )- , SingI n- , KnownPeano n ) -- | Splits a right-combed pair into @n@ elements.@@ -188,8 +293,6 @@ ':<>: 'ShowType pair ) )- , SingI ix- , KnownPeano ix ) -- | Get the node at index @ix@ of a right-combed pair.@@ -213,8 +316,6 @@ ':<>: 'ShowType pair ) )- , SingI ix- , KnownPeano ix ) -- | Update the node at index @ix@ of a right-combed pair.@@ -245,15 +346,14 @@ -- TODO [#283]: replace this wrapper with something more clever and abstract. WithLoc :: InstrCallStack -> Instr a b -> Instr a b - -- | A wrapper for an instruction that also contains annotations for- -- some of top types on the result stack.- --- -- As of now, when converting from untyped representation,- -- we only preserve field annotations and type annotations in 'Notes'.- -- Variable annotations are preserved in 'InstrWithVarAnns'.+ -- | A wrapper for instructions that, when interpreted, will+ -- place field/type annotations on one or more of the elements at+ -- the top of the stack. -- -- This can wrap only instructions with at least one non-failing execution -- branch.+ --+ -- See: Note [Annotations] InstrWithNotes :: forall a (topElems :: [T]) (s :: [T]). ( RMap topElems@@ -265,18 +365,18 @@ => Proxy s -> Rec Notes topElems -> Instr a (topElems ++ s) -> Instr a (topElems ++ s) - -- | A wrapper for an instruction which produces variable annotations on the- -- top stack element(s). See also: 'InstrWithVarAnns'.+ -- | A wrapper for instructions that have var annotations, e.g. `SOME_INSTR @ann1`.+ --+ -- This information is necessary for serializing the instruction back to json/binary.+ --+ -- See: Note [Annotations] InstrWithVarNotes :: NonEmpty VarAnn -> Instr a b -> Instr a b - -- | A wrapper for an instruction that also contains a variable annotation for- -- the top type on the result stack.+ -- | A wrapper for instructions that, when interpreted, will+ -- place var annotations on one or more of the elements at+ -- the top of the stack. --- -- This differs from 'InstrWithVarNotes' in a subtle but significant way: that- -- constructor is only present on instructions which explicitly produce- -- variable annotations, while this constructor contains the annotation- -- associated to an instruction after every type-checking phase, in the same- -- manner as 'InstrWithNotes', which is useful during the interpreter phase.+ -- See: Note [Annotations] InstrWithVarAnns :: VarAnns -> Instr a b -> Instr a b -- | Execute given instruction on truncated stack.@@ -312,92 +412,100 @@ Nested :: Instr inp out -> Instr inp out -- | Places documentation generated for given instruction under some group. -- This is not part of 'ExtInstr' because it does not behave like 'Nop';- -- instead, it inherits behaviour of instruction put within it.+ -- instead, it inherits the behaviour of the instruction put within it. DocGroup :: DocGrouping -> Instr inp out -> Instr inp out+ -- | Represents a typed stack function.+ -- This is not part of 'ExtInstr' because it does not behave like 'Nop';+ -- instead, it inherits the behaviour of the instruction put within it.+ Fn :: Text -> StackFn -> Instr inp out -> Instr inp out - -- | Variants of CAR/CDR to retain field annotations as they relate to the input- -- stack, and hence won't be available from the annotation notes from- -- the result stack we pack with the instructions during type check.- AnnCAR :: FieldAnn -> Instr ('TPair a b ': s) (a ': s)- AnnCDR :: FieldAnn -> Instr ('TPair a b ': s) (b ': s)+ -- | CAR and CDR's original annotations must be retained inside+ -- the instruction's constructor.+ -- See: Note [Annotations - Exceptional scenarios].+ AnnCAR :: VarAnn -> FieldAnn -> Instr ('TPair a b ': s) (a ': s)+ AnnCDR :: VarAnn -> FieldAnn -> Instr ('TPair a b ': s) (b ': s) -- Note that we can not merge DROP and DROPN into one instruction -- because they are packed differently. DROP :: Instr (a ': s) s DROPN :: forall (n :: Peano) s.- (SingI n, KnownPeano n, RequireLongerOrSameLength s n, NFData (Sing n))- => Sing n -> Instr s (Drop n s)- DUP :: Instr (a ': s) (a ': a ': s)+ (RequireLongerOrSameLength s n, NFData (Sing n))+ => PeanoNatural n -> Instr s (Drop n s)+ DUP :: DupableScope a => Instr (a ': s) (a ': a ': s) DUPN- :: forall (n :: Peano) inp out a. (ConstraintDUPN n inp out a, NFData (Sing n))- => Sing n -> Instr inp out+ :: forall (n :: Peano) inp out a. (ConstraintDUPN n inp out a, DupableScope a, NFData (Sing n))+ => PeanoNatural n -> Instr inp out SWAP :: Instr (a ': b ': s) (b ': a ': s) DIG :: forall (n :: Peano) inp out a. (ConstraintDIG n inp out a, NFData (Sing n))- => Sing n -> Instr inp out+ => PeanoNatural n -> Instr inp out DUG :: forall (n :: Peano) inp out a. (ConstraintDUG n inp out a, NFData (Sing n))- => Sing n -> Instr inp out+ => PeanoNatural n -> Instr inp out PUSH :: forall t s . ConstantScope t => Value' Instr t -> Instr s (t ': s) SOME :: Instr (a ': s) ('TOption a ': s)- NONE :: forall a s . KnownT a => Instr s ('TOption a ': s)+ NONE :: forall a s . SingI a => Instr s ('TOption a ': s) UNIT :: Instr s ('TUnit ': s) IF_NONE :: Instr s s' -> Instr (a ': s) s' -> Instr ('TOption a ': s) s'- -- | Annotations for PAIR instructions can be different from notes presented on the stack- -- in case of special field annotations, so we carry annotations for instruction- -- separately from notes.+ -- | PAIR's original annotations must be retained inside+ -- the instruction's constructor.+ -- See: Note [Annotations - Exceptional scenarios]. AnnPAIR :: TypeAnn -> FieldAnn -> FieldAnn -> Instr (a ': b ': s) ('TPair a b ': s)+ -- | UNPAIR's original annotations must be retained inside+ -- the instruction's constructor.+ -- See: Note [Annotations - Exceptional scenarios].+ AnnUNPAIR :: VarAnn -> VarAnn -> FieldAnn -> FieldAnn -> Instr ('TPair a b ': s) (a ': b ': s) -- |- -- >>> :t PAIRN (peanoSing @3) :: Instr '[ 'TInt, 'TUnit, 'TString ] _+ -- >>> :t PAIRN (toPeanoNatural' @3) :: Instr '[ 'TInt, 'TUnit, 'TString ] _ -- ... -- ...:: Instr -- ... '[ 'TInt, 'TUnit, 'TString] -- ... '[ 'TPair 'TInt ('TPair 'TUnit 'TString)] -- --- -- >>> PAIRN (peanoSing @1) :: Instr '[ 'TInt, 'TInt ] _+ -- >>> PAIRN (toPeanoNatural' @1) :: Instr '[ 'TInt, 'TInt ] _ -- ... -- ... 'PAIR n' expects n ≥ 2 -- ... --- -- >>> PAIRN (peanoSing @3) :: Instr '[ 'TInt, 'TInt ] _+ -- >>> PAIRN (toPeanoNatural' @3) :: Instr '[ 'TInt, 'TInt ] _ -- ... -- ... Expected stack with length >= 3 -- ... Current stack has size of only 2: -- ... PAIRN :: forall n inp. ConstraintPairN n inp- => Sing n -> Instr inp (PairN n inp)+ => PeanoNatural n -> Instr inp (PairN n inp) -- |- -- >>> :t UNPAIRN (peanoSing @3) :: Instr '[ 'TPair 'TInt ('TPair 'TUnit 'TString) ] _+ -- >>> :t UNPAIRN (toPeanoNatural' @3) :: Instr '[ 'TPair 'TInt ('TPair 'TUnit 'TString) ] _ -- ... -- ...:: Instr -- ... '[ 'TPair 'TInt ('TPair 'TUnit 'TString)] -- ... '[ 'TInt, 'TUnit, 'TString] --- -- >>> :t UNPAIRN (peanoSing @3) :: Instr '[ 'TPair 'TInt ('TPair 'TUnit ('TPair 'TString 'TNat)) ] _+ -- >>> :t UNPAIRN (toPeanoNatural' @3) :: Instr '[ 'TPair 'TInt ('TPair 'TUnit ('TPair 'TString 'TNat)) ] _ -- ... -- ...:: Instr -- ... '[ 'TPair 'TInt ('TPair 'TUnit ('TPair 'TString 'TNat))] -- ... '[ 'TInt, 'TUnit, 'TPair 'TString 'TNat] --- -- >>> UNPAIRN (peanoSing @1) :: Instr '[ 'TPair 'TInt 'TUnit ] _+ -- >>> UNPAIRN (toPeanoNatural' @1) :: Instr '[ 'TPair 'TInt 'TUnit ] _ -- ... -- ...'UNPAIR n' expects n ≥ 2 -- ... --- -- >>> UNPAIRN (peanoSing @2) :: Instr '[ 'TInt, 'TUnit, 'TString ] _+ -- >>> UNPAIRN (toPeanoNatural' @2) :: Instr '[ 'TInt, 'TUnit, 'TString ] _ -- ... -- ...Expected a pair at the top of the stack, but found: 'TInt -- ... --- -- >>> UNPAIRN (peanoSing @3) :: Instr '[ 'TPair 'TInt 'TUnit ] _+ -- >>> UNPAIRN (toPeanoNatural' @3) :: Instr '[ 'TPair 'TInt 'TUnit ] _ -- ... -- ...'UNPAIR 3' expects a right-combed pair with at least 3 elements at the top of the stack, -- ...but the pair only contains 2 elements.@@ -405,31 +513,35 @@ UNPAIRN :: forall (n :: Peano) (pair :: T) (s :: [T]). ConstraintUnpairN n pair- => Sing n+ => PeanoNatural n -> Instr (pair : s) (UnpairN n pair ++ s)- AnnLEFT :: KnownT b => TypeAnn -> FieldAnn -> FieldAnn -> Instr (a ': s) ('TOr a b ': s)- AnnRIGHT :: KnownT a => TypeAnn -> FieldAnn -> FieldAnn -> Instr (b ': s) ('TOr a b ': s)++ -- | LEFT and RIGHT's original annotations must be retained inside+ -- the instruction's constructor.+ -- See: Note [Annotations - Exceptional scenarios].+ AnnLEFT :: SingI b => TypeAnn -> FieldAnn -> FieldAnn -> Instr (a ': s) ('TOr a b ': s)+ AnnRIGHT :: SingI a => TypeAnn -> FieldAnn -> FieldAnn -> Instr (b ': s) ('TOr a b ': s) IF_LEFT :: Instr (a ': s) s' -> Instr (b ': s) s' -> Instr ('TOr a b ': s) s'- NIL :: KnownT p => Instr s ('TList p ': s)+ NIL :: SingI p => Instr s ('TList p ': s) CONS :: Instr (a ': 'TList a ': s) ('TList a ': s) IF_CONS :: Instr (a ': 'TList a ': s) s' -> Instr s s' -> Instr ('TList a ': s) s' SIZE :: SizeOp c => Instr (c ': s) ('TNat ': s)- EMPTY_SET :: (KnownT e, Comparable e) => Instr s ('TSet e ': s)- EMPTY_MAP :: (KnownT a, KnownT b, Comparable a) => Instr s ('TMap a b ': s)- EMPTY_BIG_MAP :: (KnownT a, KnownT b, Comparable a) => Instr s ('TBigMap a b ': s)- MAP :: (MapOp c, KnownT b)+ EMPTY_SET :: (SingI e, Comparable e) => Instr s ('TSet e ': s)+ EMPTY_MAP :: (SingI a, SingI b, Comparable a) => Instr s ('TMap a b ': s)+ EMPTY_BIG_MAP :: (SingI a, SingI b, Comparable a, HasNoBigMap b) => Instr s ('TBigMap a b ': s)+ MAP :: (MapOp c, SingI b) => Instr (MapOpInp c ': s) (b ': s) -> Instr (c ': s) (MapOpRes c b ': s) ITER :: IterOp c => Instr (IterOpEl c ': s) s -> Instr (c ': s) s MEM :: MemOp c => Instr (MemOpKey c ': c ': s) ('TBool ': s) GET- :: (GetOp c, KnownT (GetOpVal c))+ :: (GetOp c, SingI (GetOpVal c)) => Instr (GetOpKey c ': c ': s) ('TOption (GetOpVal c) ': s) -- | Get the node at index @ix@ of a right-combed pair. -- Nodes are 0-indexed, and are numbered in a breadth-first,@@ -452,16 +564,16 @@ -- > / \ -- > 3 4 --- -- >>> :t GETN (peanoSing @1) :: Instr '[ 'TPair 'TInt 'TUnit] _+ -- >>> :t GETN (toPeanoNatural' @1) :: Instr '[ 'TPair 'TInt 'TUnit] _ -- ... -- ...:: Instr '[ 'TPair 'TInt 'TUnit] '[ 'TInt] --- -- >>> GETN (peanoSing @1) :: Instr '[ 'TUnit ] _+ -- >>> GETN (toPeanoNatural' @1) :: Instr '[ 'TUnit ] _ -- ... -- ...Expected a pair at the top of the stack, but found: 'TUnit -- ... --- -- >>> GETN (peanoSing @3) :: Instr '[ 'TPair 'TInt 'TUnit ] _+ -- >>> GETN (toPeanoNatural' @3) :: Instr '[ 'TPair 'TInt 'TUnit ] _ -- ... -- ...'GET 3' expects a right-combed pair with at least 4 nodes at the top of the stack, -- ...but the pair only contains 3 nodes.@@ -469,30 +581,30 @@ -- -- Note that @GET 0@ is just the identity function and works for all types (not just pairs). --- -- >>> :t GETN (peanoSing @0) :: Instr '[ 'TInt ] _+ -- >>> :t GETN (toPeanoNatural' @0) :: Instr '[ 'TInt ] _ -- ... -- ...:: Instr '[ 'TInt] '[ 'TInt] GETN :: forall (ix :: Peano) (pair :: T) (s :: [T]). ConstraintGetN ix pair- => Sing ix+ => PeanoNatural ix -> Instr (pair : s) (GetN ix pair ': s) UPDATE :: UpdOp c => Instr (UpdOpKey c ': UpdOpParams c ': c ': s) (c ': s) -- | Update the node at index @ix@ of a right-combed pair. --- -- >>> :t UPDATEN (peanoSing @1) :: Instr '[ 'TString, 'TPair 'TInt 'TUnit] _+ -- >>> :t UPDATEN (toPeanoNatural' @1) :: Instr '[ 'TString, 'TPair 'TInt 'TUnit] _ -- ... -- ...:: Instr -- ... '[ 'TString, 'TPair 'TInt 'TUnit] '[ 'TPair 'TString 'TUnit] --- -- >>> UPDATEN (peanoSing @1) :: Instr '[ 'TUnit, 'TInt ] _+ -- >>> UPDATEN (toPeanoNatural' @1) :: Instr '[ 'TUnit, 'TInt ] _ -- ... -- ...Expected the 2nd element of the stack to be a pair, but found: 'TInt -- ... --- -- >>> UPDATEN (peanoSing @3) :: Instr '[ 'TString, 'TPair 'TInt 'TUnit ] _+ -- >>> UPDATEN (toPeanoNatural' @3) :: Instr '[ 'TString, 'TPair 'TInt 'TUnit ] _ -- ... -- ...'UPDATE 3' expects the 2nd element of the stack to be a right-combed pair with at least 4 nodes, -- ...but the pair only contains 3 nodes.@@ -500,16 +612,16 @@ -- -- Note that @UPDATE 0@ is equivalent to @DIP { DROP }@. --- -- >>> :t UPDATEN (peanoSing @0) :: Instr '[ 'TInt, 'TString ] _+ -- >>> :t UPDATEN (toPeanoNatural' @0) :: Instr '[ 'TInt, 'TString ] _ -- ... -- ...:: Instr '[ 'TInt, 'TString] '[ 'TInt] UPDATEN :: forall (ix :: Peano) (val :: T) (pair :: T) (s :: [T]). ConstraintUpdateN ix pair- => Sing ix+ => PeanoNatural ix -> Instr (val : pair : s) (UpdateN ix val pair ': s) GET_AND_UPDATE- :: ( GetOp c, UpdOp c, KnownT (GetOpVal c)+ :: ( GetOp c, UpdOp c, SingI (GetOpVal c) , UpdOpKey c ~ GetOpKey c ) => Instr (UpdOpKey c ': UpdOpParams c ': c ': s) ('TOption (GetOpVal c) : c ': s)@@ -521,28 +633,28 @@ LOOP_LEFT :: Instr (a ': s) ('TOr a b ': s) -> Instr ('TOr a b ': s) (b ': s)- LAMBDA :: forall i o s . (KnownT i, KnownT o)+ LAMBDA :: forall i o s . (SingI i, SingI o) => Value' Instr ('TLambda i o) -> Instr s ('TLambda i o ': s) EXEC :: Instr (t1 ': 'TLambda t1 t2 ': s) (t2 ': s) APPLY- :: forall a b c s . (ConstantScope a, KnownT b)+ :: forall a b c s . (ConstantScope a, SingI b) => Instr (a ': 'TLambda ('TPair a b) c ': s) ('TLambda b c ': s) DIP :: Instr a c -> Instr (b ': a) (b ': c) DIPN :: forall (n :: Peano) inp out s s'. (ConstraintDIPN n inp out s s', (NFData (Sing n)))- => Sing n -> Instr s s' -> Instr inp out+ => PeanoNatural n -> Instr s s' -> Instr inp out -- Since 008 it's prohibited to fail with non-packable values and with the -- 'Contract t' type values, which is equivalent to our @ConstantScope@ constraint. -- See https://gitlab.com/tezos/tezos/-/issues/1093#note_496066354 for more information.- FAILWITH :: (KnownT a, ConstantScope a) => Instr (a ': s) t+ FAILWITH :: (SingI a, ConstantScope a) => Instr (a ': s) t CAST :: forall a s . SingI a => Instr (a ': s) (a ': s) RENAME :: Instr (a ': s) (a ': s) PACK :: PackedValScope a => Instr (a ': s) ('TBytes ': s)- UNPACK :: (UnpackedValScope a, KnownT a) => Instr ('TBytes ': s) ('TOption a ': s)+ UNPACK :: (UnpackedValScope a, SingI a) => Instr ('TBytes ': s) ('TOption a ': s) CONCAT :: ConcatOp c => Instr (c ': c ': s) (c ': s) CONCAT' :: ConcatOp c => Instr ('TList c ': s) (c ': s) SLICE- :: (SliceOp c, KnownT c)+ :: (SliceOp c, SingI c) => Instr ('TNat ': 'TNat ': c ': s) ('TOption c ': s) ISNAT :: Instr ('TInt ': s) ('TOption ('TNat) ': s) ADD@@ -584,7 +696,7 @@ :: UnaryArithOp Not n => Instr (n ': s) (UnaryArithRes Not n ': s) COMPARE- :: (Comparable n, KnownT n)+ :: (Comparable n, SingI n) => Instr (n ': n ': s) ('TInt ': s) EQ :: UnaryArithOp Eq' n@@ -656,7 +768,40 @@ LEVEL :: Instr s ('TNat ': s) SELF_ADDRESS :: Instr s ('TAddress ': s) NEVER :: Instr ('TNever ': s) t+ TICKET+ :: (Comparable a)+ => Instr (a ': 'TNat ': s) ('TTicket a ': s)+ READ_TICKET+ :: Instr ('TTicket a ': s)+ (RightComb ['TAddress, a, 'TNat] ': 'TTicket a ': s)+ SPLIT_TICKET+ :: Instr ('TTicket a ': 'TPair 'TNat 'TNat ': s)+ ('TOption ('TPair ('TTicket a) ('TTicket a)) ': s)+ JOIN_TICKETS+ :: Instr ('TPair ('TTicket a) ('TTicket a) ': s)+ ('TOption ('TTicket a) ': s) +castInstr+ :: forall inp1 out1 inp2 out2.+ ( SingI inp1+ , SingI out1+ , SingI inp2+ , SingI out2+ )+ => Instr inp1 out1 -> Maybe (Instr inp2 out2)+castInstr instr =+ case (eqI @inp1 @inp2, eqI @out1 @out2) of+ (Just Refl, Just Refl) -> Just instr+ (_,_) -> Nothing++-- | Right-associative operator for 'Seq'.+--+-- >>> show (DROP :# UNIT :# Nop) == show (DROP :# (UNIT :# Nop))+-- True+pattern (:#) :: Instr a b -> Instr b c -> Instr a c+pattern a :# b = Seq a b+infixr 8 :#+ deriving stock instance Show (Instr inp out) instance Semigroup (Instr s s) where@@ -673,26 +818,26 @@ -- -- Note that internally GADT constructors are rewritten in the very same way. pattern CAR :: () => (i ~ ('TPair a b : s), o ~ (a : s)) => Instr i o-pattern CAR = AnnCAR (AnnotationUnsafe "")+pattern CAR = AnnCAR (UnsafeAnnotation "") (UnsafeAnnotation "") pattern CDR :: () => (i ~ ('TPair a b : s), o ~ (b : s)) => Instr i o-pattern CDR = AnnCDR (AnnotationUnsafe "")+pattern CDR = AnnCDR (UnsafeAnnotation "") (UnsafeAnnotation "") pattern UNPAIR :: () => (i ~ ('TPair a b : s), o ~ (a : b : s)) => Instr i o-pattern UNPAIR = Seq DUP (Seq CAR (DIP CDR))+pattern UNPAIR = AnnUNPAIR (UnsafeAnnotation "") (UnsafeAnnotation "") (UnsafeAnnotation "") (UnsafeAnnotation "") pattern PAIR :: () => (i ~ (a ': b ': s), o ~ ('TPair a b ': s)) => Instr i o-pattern PAIR = AnnPAIR (AnnotationUnsafe "") (AnnotationUnsafe "") (AnnotationUnsafe "")+pattern PAIR = AnnPAIR (UnsafeAnnotation "") (UnsafeAnnotation "") (UnsafeAnnotation "") -pattern LEFT :: () => (KnownT b, i ~ (a ': s), o ~ ('TOr a b ': s)) => Instr i o-pattern LEFT = AnnLEFT (AnnotationUnsafe "") (AnnotationUnsafe "") (AnnotationUnsafe "")+pattern LEFT :: () => (SingI b, i ~ (a ': s), o ~ ('TOr a b ': s)) => Instr i o+pattern LEFT = AnnLEFT (UnsafeAnnotation "") (UnsafeAnnotation "") (UnsafeAnnotation "") -pattern RIGHT :: () => (KnownT a, i ~ (b ': s), o ~ ('TOr a b ': s)) => Instr i o-pattern RIGHT = AnnRIGHT (AnnotationUnsafe "") (AnnotationUnsafe "") (AnnotationUnsafe "")+pattern RIGHT :: () => (SingI a, i ~ (b ': s), o ~ ('TOr a b ': s)) => Instr i o+pattern RIGHT = AnnRIGHT (UnsafeAnnotation "") (UnsafeAnnotation "") (UnsafeAnnotation "") data TestAssert (s :: [T]) where TestAssert- :: (Typeable out)+ :: (SingI out) => Text -> PrintComment inp -> Instr inp ('TBool ': out)@@ -706,24 +851,24 @@ data StackRef (st :: [T]) where -- | Keeps 0-based index to a stack element counting from the top. StackRef- :: (KnownPeano idx, SingI idx, RequireLongerThan st idx)- => Sing (idx :: Peano) -> StackRef st+ :: (RequireLongerThan st idx)+ => PeanoNatural idx -> StackRef st instance NFData (StackRef st) where rnf (StackRef s) = rnf s instance Eq (StackRef st) where- StackRef snat1 == StackRef snat2 = peanoVal snat1 == peanoVal snat2+ StackRef snat1 == StackRef snat2 = fromPeanoNatural snat1 == fromPeanoNatural snat2 instance Show (StackRef st) where- show (StackRef snat) = "StackRef {" +|| peanoVal snat ||+ "}"+ show (StackRef snat) = "StackRef {" +|| fromPeanoNatural snat ||+ "}" -- | Create a stack reference, performing checks at compile time. mkStackRef :: forall (gn :: GHC.Nat) st n.- (n ~ ToPeano gn, SingI n, KnownPeano n, RequireLongerThan st n)+ (n ~ ToPeano gn, SingI (ToPeano gn), RequireLongerThan st n) => StackRef st-mkStackRef = StackRef $ peanoSing @gn+mkStackRef = StackRef $ toPeanoNatural' @gn -- | A print format with references into the stack newtype PrintComment (st :: [T]) = PrintComment@@ -752,6 +897,7 @@ | PRINT (PrintComment s) | DOC_ITEM SomeDocItem | COMMENT_ITEM CommentType+ | STACKTYPE StackTypePattern deriving stock (Show, Generic) instance NFData (ExtInstr s)
src/Michelson/Typed/Origination.hs view
@@ -5,18 +5,25 @@ module Michelson.Typed.Origination ( OriginationOperation(..) , mkOriginationOperationHash++ -- * Operation hashing+ , OperationHash (..)+ , mkContractAddress+ ) where -import Data.Binary.Put (putWord64be, runPut)+import Data.Binary.Put (putInt32be, putWord64be, runPut) import qualified Data.ByteString.Lazy as BSL -import Michelson.Interpret.Pack (encodeKeyHashRaw, encodeValue', packCode')+import Michelson.Interpret.Pack (toBinary') import Michelson.Typed.Aliases (Value)+import Michelson.Typed.Haskell.Value (IsoValue(..)) import Michelson.Typed.Instr (Contract(..), cCode) import Michelson.Typed.Scope (ParameterScope, StorageScope)-import Tezos.Address (Address, OperationHash(..))+import Tezos.Address+ (Address(ContractAddress), ContractHash(..), GlobalCounter(..), OriginationIndex(..)) import Tezos.Core (Mutez(..))-import Tezos.Crypto (KeyHash, blake2b)+import Tezos.Crypto (KeyHash, blake2b, blake2b160) -- | Data necessary to originate a contract. data OriginationOperation =@@ -49,9 +56,9 @@ -- and https://gitlab.com/tezos/tezos/-/blob/f57c50e3a657956d69a1699978de9873c98f0018/src/proto_006_PsCARTHA/lib_protocol/script_repr.ml#L68 packedOperation = BSL.toStrict (runPut $ putWord64be $ unMutez ooBalance)- <> packMaybe (BSL.toStrict . encodeKeyHashRaw) ooDelegate- <> packCode' (cCode ooContract)- <> encodeValue' ooStorage+ <> packMaybe (toBinary' . toVal) ooDelegate+ <> toBinary' (cCode ooContract)+ <> toBinary' ooStorage -- "optional" encoding in Tezos. --@@ -59,3 +66,45 @@ packMaybe :: (a -> ByteString) -> Maybe a -> ByteString packMaybe _ Nothing = "\255" packMaybe f (Just a) = "\0" <> f a++----------------------------------------------------------------------------+-- Operation hash+----------------------------------------------------------------------------++newtype OperationHash = OperationHash+ { unOperationHash :: ByteString+ }+ deriving stock (Show, Eq, Ord, Generic)+ deriving anyclass (NFData)++-- | Compute address of a contract from its origination operation, origination index and global counter.+--+-- However, in real Tezos encoding of the operation is more than just 'OriginationOperation'.+-- There an Operation has several more meta-fields plus a big sum-type of all possible operations.+--+-- See here: https://gitlab.com/tezos/tezos/-/blob/f57c50e3a657956d69a1699978de9873c98f0018/src/proto_006_PsCARTHA/lib_protocol/operation_repr.ml#L78+--+-- What is important is that one (big) Operation may lead to origination of multiple contracts. That+-- is why contract address is constructed from hash of the operation that originated and of index+-- of the contract's origination in the execution of that operation.+--+-- In other words, contract hash is calculated as the blake2b160 (20-byte) hash of+-- origination operation hash + int32 origination index + word64 global counter.+--+-- In Morley we do not yet support full encoding of Tezos Operations, therefore we choose+-- to generate contract addresses in a simplified manner.+--+-- Namely, we encode 'OriginationOperation' as we can and concat it with the origination index+-- and the global counter.+-- Then we take 'blake2b160' hash of the resulting bytes and consider it to be the contract's+-- address.+mkContractAddress+ :: OperationHash+ -> OriginationIndex+ -> GlobalCounter+ -> Address+mkContractAddress (OperationHash opHash) (OriginationIndex idx) (GlobalCounter counter) =+ ContractAddress+ $ ContractHash+ $ blake2b160+ $ opHash <> BSL.toStrict (runPut $ putInt32be idx >> putWord64be counter)
src/Michelson/Typed/Polymorphic.hs view
@@ -22,10 +22,10 @@ import qualified Data.ByteString as B import qualified Data.Map as M import qualified Data.Set as S+import Data.Singletons (SingI) import Michelson.Text import Michelson.Typed.Annotation-import Michelson.Typed.Sing (KnownT) import Michelson.Typed.T (T(..)) import Michelson.Typed.Value (Value'(..)) import Michelson.Untyped.Annotation (noAnn)@@ -43,14 +43,14 @@ evalMem k (VMap m) = k `M.member` m instance MemOp ('TBigMap k v) where type MemOpKey ('TBigMap k v) = k- evalMem k (VBigMap m) = k `M.member` m+ evalMem k (VBigMap _ m) = k `M.member` m class MapOp (c :: T) where type MapOpInp c :: T type MapOpRes c :: T -> T mapOpToList :: Value' instr c -> [Value' instr (MapOpInp c)] mapOpFromList- :: (KnownT b)+ :: (SingI b) => Value' instr c -> [Value' instr b] -> Value' instr (MapOpRes c b) mapOpNotes :: Notes c -> Notes (MapOpInp c) instance MapOp ('TMap k v) where@@ -121,10 +121,10 @@ instance UpdOp ('TBigMap k v) where type UpdOpKey ('TBigMap k v) = k type UpdOpParams ('TBigMap k v) = 'TOption v- evalUpd k (VOption o) (VBigMap m) =+ evalUpd k (VOption o) (VBigMap bmId m) = case o of- Just newV -> VBigMap $ M.insert k newV m- Nothing -> VBigMap $ M.delete k m+ Just newV -> VBigMap bmId $ M.insert k newV m+ Nothing -> VBigMap bmId $ M.delete k m instance UpdOp ('TSet a) where type UpdOpKey ('TSet a) = a type UpdOpParams ('TSet a) = 'TBool@@ -140,7 +140,7 @@ instance GetOp ('TBigMap k v) where type GetOpKey ('TBigMap k v) = k type GetOpVal ('TBigMap k v) = v- evalGet k (VBigMap m) = k `M.lookup` m+ evalGet k (VBigMap _ m) = k `M.lookup` m instance GetOp ('TMap k v) where type GetOpKey ('TMap k v) = k type GetOpVal ('TMap k v) = v
src/Michelson/Typed/Scope.hs view
@@ -38,6 +38,7 @@ module Michelson.Typed.Scope ( -- * Scopes ConstantScope+ , DupableScope , StorageScope , PackedValScope , ParameterScope@@ -47,6 +48,7 @@ , ProperParameterBetterErrors , ProperStorageBetterErrors , ProperConstantBetterErrors+ , ProperDupableBetterErrors , ProperPackedValBetterErrors , ProperUnpackedValBetterErrors , ProperPrintedValBetterErrors@@ -54,6 +56,7 @@ , properParameterEvi , properStorageEvi , properConstantEvi+ , properDupableEvi , properPackedValEvi , properUnpackedValEvi , properPrintedValEvi@@ -68,11 +71,13 @@ , HasNoNestedBigMaps , HasNoOp , HasNoContract+ , HasNoTicket , ContainsBigMap , ContainsNestedBigMaps , ForbidOp , ForbidContract+ , ForbidTicket , ForbidBigMap , ForbidNestedBigMaps , FailOnBigMapFound@@ -81,10 +86,12 @@ , OpPresence (..) , ContractPresence (..)+ , TicketPresence (..) , BigMapPresence (..) , NestedBigMapsPresence (..) , checkOpPresence , checkContractTypePresence+ , checkTicketPresence , checkBigMapPresence , checkNestedBigMapsPresence , opAbsense@@ -101,19 +108,20 @@ , SingI (..) ) where -import Data.Constraint ((:-)(..), Dict(..), withDict, (\\))+import Data.Constraint (Dict(..), withDict, (:-)(..), (\\)) import Data.Singletons (Sing, SingI(..)) import Data.Type.Bool (type (||)) import Fmt (Buildable(..)) import GHC.TypeLits (ErrorMessage(..), TypeError) -import Michelson.Typed.Sing (KnownT, SingT(..))+import Michelson.Typed.Sing (SingT(..)) import Michelson.Typed.T (T(..))+import Michelson.Printer.Util (RenderDoc(..), buildRenderDoc) ---------------------------------------------------------------------------- -- Constraints ------------------------------------------------------------------------------- | Whether this type contains 'TOperation' type.+-- | Whether a value of this type _may_ contain an operation. -- -- In some scopes (constants, parameters, storage) appearing for operation type -- is prohibited.@@ -127,7 +135,8 @@ ContainsOp ('TList t) = ContainsOp t ContainsOp ('TSet t) = ContainsOp t ContainsOp 'TOperation = 'True- ContainsOp ('TContract t) = ContainsOp t+ ContainsOp ('TContract _) = 'False+ ContainsOp ('TTicket t) = ContainsOp t ContainsOp ('TPair a b) = ContainsOp a || ContainsOp b ContainsOp ('TOr a b) = ContainsOp a || ContainsOp b ContainsOp ('TLambda _ _) = 'False@@ -135,7 +144,7 @@ ContainsOp ('TBigMap k v) = ContainsOp k || ContainsOp v ContainsOp _ = 'False --- | Whether this type contains 'TContract' type.+-- | Whether a value of this type _may_ contain a @contract@ value. -- -- In some scopes (constants, storage) appearing for contract type -- is prohibited.@@ -157,7 +166,20 @@ ContainsContract ('TBigMap _ v) = ContainsContract v ContainsContract _ = 'False --- | Whether this type contains 'TBigMap' type.+-- | Whether a value of this type _may_ contain a @ticket@ value.+type family ContainsTicket (t :: T) :: Bool where+ ContainsTicket ('TOption t) = ContainsTicket t+ ContainsTicket ('TList t) = ContainsTicket t+ ContainsTicket ('TSet _) = 'False+ ContainsTicket ('TTicket _) = 'True+ ContainsTicket ('TPair a b) = ContainsTicket a || ContainsTicket b+ ContainsTicket ('TOr a b) = ContainsTicket a || ContainsTicket b+ ContainsTicket ('TLambda _ _) = 'False+ ContainsTicket ('TMap _ v) = ContainsTicket v+ ContainsTicket ('TBigMap _ v) = ContainsTicket v+ ContainsTicket _ = 'False++-- | Whether a value of this type _may_ contain a @big_map@ value. type family ContainsBigMap (t :: T) :: Bool where ContainsBigMap 'TKey = 'False ContainsBigMap 'TUnit = 'False@@ -167,7 +189,7 @@ ContainsBigMap ('TList t) = ContainsBigMap t ContainsBigMap ('TSet _) = 'False ContainsBigMap 'TOperation = 'False- ContainsBigMap ('TContract t) = ContainsBigMap t+ ContainsBigMap ('TContract _) = 'False ContainsBigMap ('TPair a b) = ContainsBigMap a || ContainsBigMap b ContainsBigMap ('TOr a b) = ContainsBigMap a || ContainsBigMap b ContainsBigMap ('TLambda _ _) = 'False@@ -175,11 +197,11 @@ ContainsBigMap ('TBigMap _ _) = 'True ContainsBigMap _ = 'False --- | Whether this type contains a type with nested 'TBigMap's .+-- | Whether a value of this type _may_ contain nested @big_map@s. ----- Nested big_maps (i.e. big_map which contains another big_map inside of it's value type). Are+-- Nested big_maps (i.e. big_map which contains another big_map inside of it's value type) are -- prohibited in all contexts. Some context such as PUSH, APPLY, PACK/UNPACK instructions are more--- strict because they doesn't work with big_map at all.+-- strict because they don't work with big_map at all. type family ContainsNestedBigMaps (t :: T) :: Bool where ContainsNestedBigMaps 'TKey = 'False ContainsNestedBigMaps 'TUnit = 'False@@ -189,7 +211,7 @@ ContainsNestedBigMaps ('TList t) = ContainsNestedBigMaps t ContainsNestedBigMaps ('TSet _) = 'False ContainsNestedBigMaps 'TOperation = 'False- ContainsNestedBigMaps ('TContract t) = ContainsNestedBigMaps t+ ContainsNestedBigMaps ('TContract _) = 'False ContainsNestedBigMaps ('TPair a b) = ContainsNestedBigMaps a || ContainsNestedBigMaps b ContainsNestedBigMaps ('TOr a b) = ContainsNestedBigMaps a || ContainsNestedBigMaps b ContainsNestedBigMaps ('TLambda _ _) = 'False@@ -197,18 +219,22 @@ ContainsNestedBigMaps ('TBigMap _ v) = ContainsBigMap v ContainsNestedBigMaps _ = 'False --- | Constraint which ensures that operation type does not appear in a given type.+-- | Constraint which ensures that a value of type @t@ does not contain operations. -- -- Not just a type alias in order to be able to partially apply it -- (e.g. in 'Each'). class (ContainsOp t ~ 'False) => HasNoOp t instance (ContainsOp t ~ 'False) => HasNoOp t --- | Constraint which ensures that contract type does not appear in a given type.+-- | Constraint which ensures that a value of type @t@ does not contain @contract@ values. class (ContainsContract t ~ 'False) => HasNoContract t instance (ContainsContract t ~ 'False) => HasNoContract t --- | Constraint which ensures that bigmap does not appear in a given type.+-- | Constraint which ensures that a value of type @t@ does not contain @ticket@ values.+class (ContainsTicket t ~ 'False) => HasNoTicket t+instance (ContainsTicket t ~ 'False) => HasNoTicket t++-- | Constraint which ensures that a value of type @t@ does not contain @big_map@ values. class (ContainsBigMap t ~ 'False) => HasNoBigMap t instance (ContainsBigMap t ~ 'False) => HasNoBigMap t @@ -228,6 +254,12 @@ TypeError ('Text "Type `contract` is not allowed in this scope") FailOnContractFound 'False = () +-- | Report a human-readable error about 'TTicket' at a wrong place.+type family FailOnTicketFound (enabled :: Bool) :: Constraint where+ FailOnTicketFound 'True =+ TypeError ('Text "Type `ticket` is not allowed in this scope")+ FailOnTicketFound 'False = ()+ -- | Report a human-readable error about 'TBigMap' at a wrong place. type family FailOnBigMapFound (enabled :: Bool) :: Constraint where FailOnBigMapFound 'True =@@ -251,6 +283,8 @@ type ForbidContract t = FailOnContractFound (ContainsContract t) +type ForbidTicket t = FailOnTicketFound (ContainsTicket t)+ type ForbidBigMap t = FailOnBigMapFound (ContainsBigMap t) type ForbidNestedBigMaps t = FailOnNestedBigMapsFound (ContainsNestedBigMaps t)@@ -317,29 +351,55 @@ -> a forbiddenContractType = withDict $ forbiddenContractTypeEvi @t --- | Whether the type contains 'TOperation', with proof.+-- | Reify 'HasNoTicket' contraint from 'ForbidTicket'.+forbiddenTicketTypeEvi+ :: forall t. (SingI t, ForbidTicket t) :- HasNoTicket t+forbiddenTicketTypeEvi = Sub $+ case checkTicketPresence (sing @t) of+ TicketAbsent -> Dict+ TicketPresent -> error "impossible"++-- | Whether a value of this type _may_ contain an operation. data OpPresence (t :: T) = ContainsOp t ~ 'True => OpPresent+ -- ^ A value of type @t@ may or may not contain an operation. | ContainsOp t ~ 'False => OpAbsent+ -- ^ A value of type @t@ cannot contain @big_map@ values. +-- | Whether a value of this type _may_ contain a @contract@ value. data ContractPresence (t :: T) = ContainsContract t ~ 'True => ContractPresent+ -- ^ A value of type @t@ may or may not contain a @contract@ value. | ContainsContract t ~ 'False => ContractAbsent+ -- ^ A value of type @t@ cannot contain @contract@ values. +-- | Whether a value of this type _may_ contain a @ticket@ value.+data TicketPresence (t :: T)+ = ContainsTicket t ~ 'True => TicketPresent+ -- ^ A value of type @t@ may or may not contain a @ticket@ value.+ | ContainsTicket t ~ 'False => TicketAbsent+ -- ^ A value of type @t@ cannot contain @ticket@ values.++-- | Whether a value of this type _may_ contain a @big_map@ value. data BigMapPresence (t :: T) = ContainsBigMap t ~ 'True => BigMapPresent+ -- ^ A value of type @t@ may or may not contain a @big_map@ value. | ContainsBigMap t ~ 'False => BigMapAbsent+ -- ^ A value of type @t@ cannot contain @big_map@ values. +-- | Whether a value of this type _may_ contain nested @big_map@s. data NestedBigMapsPresence (t :: T) = ContainsNestedBigMaps t ~ 'True => NestedBigMapsPresent+ -- ^ A value of type @t@ may or may not contain nested @big_map@s. | ContainsNestedBigMaps t ~ 'False => NestedBigMapsAbsent+ -- ^ A value of type @t@ cannot contain nested @big_map@s. -- @rvem: IMO, generalization of OpPresence and BigMapPresence to -- TPresence is not worth it, due to the fact that -- it will require more boilerplate in checkTPresence implementation -- than it is already done in checkOpPresence and checkBigMapPresence --- | Check at runtime whether the given type contains 'TOperation'.+-- | Check at runtime whether a value of the given type _may_ contain an operation. checkOpPresence :: Sing (ty :: T) -> OpPresence ty checkOpPresence = \case -- This is a sad amount of boilerplate, but at least@@ -361,7 +421,8 @@ OpPresent -> OpPresent OpAbsent -> OpAbsent STOperation -> OpPresent- STContract t -> case checkOpPresence t of+ STContract _ -> OpAbsent+ STTicket t -> case checkOpPresence t of OpPresent -> OpPresent OpAbsent -> OpAbsent STPair a b -> case (checkOpPresence a, checkOpPresence b) of@@ -395,7 +456,7 @@ STAddress -> OpAbsent STNever -> OpAbsent --- | Check at runtime whether the given type contains 'TContract'.+-- | Check at runtime whether a value of the given type _may_ contain a @contract@ value. checkContractTypePresence :: Sing (ty :: T) -> ContractPresence ty checkContractTypePresence = \case STKey -> ContractAbsent@@ -411,6 +472,7 @@ STSet _ -> ContractAbsent STOperation -> ContractAbsent STContract _ -> ContractPresent+ STTicket _ -> ContractAbsent -- contract type is not allowed in tickets at all STPair a b -> case (checkContractTypePresence a, checkContractTypePresence b) of (ContractPresent, _) -> ContractPresent (_, ContractPresent) -> ContractPresent@@ -440,7 +502,53 @@ STAddress -> ContractAbsent STNever -> ContractAbsent --- | Check at runtime whether the given type contains 'TBigMap'.+-- | Check at runtime whether a value of the given type _may_ contain a @ticket@ value.+checkTicketPresence :: Sing (ty :: T) -> TicketPresence ty+checkTicketPresence = \case+ STKey -> TicketAbsent+ STSignature -> TicketAbsent+ STChainId -> TicketAbsent+ STUnit -> TicketAbsent+ STOption t -> case checkTicketPresence t of+ TicketPresent -> TicketPresent+ TicketAbsent -> TicketAbsent+ STList t -> case checkTicketPresence t of+ TicketPresent -> TicketPresent+ TicketAbsent -> TicketAbsent+ STSet _ -> TicketAbsent+ STOperation -> TicketAbsent+ STContract _ -> TicketAbsent+ STTicket _ -> TicketPresent+ STPair a b -> case (checkTicketPresence a, checkTicketPresence b) of+ (TicketPresent, _) -> TicketPresent+ (_, TicketPresent) -> TicketPresent+ (TicketAbsent, TicketAbsent) -> TicketAbsent+ STOr a b -> case (checkTicketPresence a, checkTicketPresence b) of+ (TicketPresent, _) -> TicketPresent+ (_, TicketPresent) -> TicketPresent+ (TicketAbsent, TicketAbsent) -> TicketAbsent+ STLambda _ _ -> TicketAbsent+ STMap _ v -> case checkTicketPresence v of+ TicketPresent -> TicketPresent+ TicketAbsent -> TicketAbsent+ STBigMap _ v -> case checkTicketPresence v of+ TicketPresent -> TicketPresent+ TicketAbsent -> TicketAbsent+ STInt -> TicketAbsent+ STNat -> TicketAbsent+ STString -> TicketAbsent+ STBytes -> TicketAbsent+ STMutez -> TicketAbsent+ STBool -> TicketAbsent+ STKeyHash -> TicketAbsent+ STBls12381Fr -> TicketAbsent+ STBls12381G1 -> TicketAbsent+ STBls12381G2 -> TicketAbsent+ STTimestamp -> TicketAbsent+ STAddress -> TicketAbsent+ STNever -> TicketAbsent++-- | Check at runtime whether a value of the given type _may_ contain a @big_map@ value. checkBigMapPresence :: Sing (ty :: T) -> BigMapPresence ty checkBigMapPresence = \case -- More boilerplate to boilerplate god.@@ -456,9 +564,8 @@ BigMapAbsent -> BigMapAbsent STSet _ -> BigMapAbsent STOperation -> BigMapAbsent- STContract t -> case checkBigMapPresence t of- BigMapPresent -> BigMapPresent- BigMapAbsent -> BigMapAbsent+ STContract _ -> BigMapAbsent+ STTicket _ -> BigMapAbsent -- big_maps are not allowed in tickets at all STPair a b -> case (checkBigMapPresence a, checkBigMapPresence b) of (BigMapPresent, _) -> BigMapPresent (_, BigMapPresent) -> BigMapPresent@@ -487,7 +594,7 @@ STAddress -> BigMapAbsent STNever -> BigMapAbsent --- | Check at runtime whether the given type contains 'TBigMap'.+-- | Check at runtime whether a value of the given type _may_ contain nested @big_map@s. checkNestedBigMapsPresence :: Sing (ty :: T) -> NestedBigMapsPresence ty checkNestedBigMapsPresence = \case -- More boilerplate to boilerplate god.@@ -503,9 +610,8 @@ NestedBigMapsAbsent -> NestedBigMapsAbsent STSet _ -> NestedBigMapsAbsent STOperation -> NestedBigMapsAbsent- STContract t -> case checkNestedBigMapsPresence t of- NestedBigMapsPresent -> NestedBigMapsPresent- NestedBigMapsAbsent -> NestedBigMapsAbsent+ STContract _ -> NestedBigMapsAbsent+ STTicket _ -> NestedBigMapsAbsent STPair a b -> case (checkNestedBigMapsPresence a, checkNestedBigMapsPresence b) of (NestedBigMapsPresent, _) -> NestedBigMapsPresent (_, NestedBigMapsPresent) -> NestedBigMapsPresent@@ -535,25 +641,31 @@ STAddress -> NestedBigMapsAbsent STNever -> NestedBigMapsAbsent --- | Check at runtime that the given type does not contain 'TOperation'.+-- | Check at runtime that a value of the given type cannot contain operations. opAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoOp t) opAbsense s = case checkOpPresence s of OpPresent -> Nothing OpAbsent -> Just Dict --- | Check at runtime that the given type does not contain 'TContract'.+-- | Check at runtime that a value of the given type cannot contain @contract@ values. contractTypeAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoContract t) contractTypeAbsense s = case checkContractTypePresence s of ContractPresent -> Nothing ContractAbsent -> Just Dict --- | Check at runtime that the given type does not containt 'TBigMap'+-- | Check at runtime that a value of the given type cannot contain @ticket@ values.+ticketAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoTicket t)+ticketAbsense s = case checkTicketPresence s of+ TicketPresent -> Nothing+ TicketAbsent -> Just Dict++-- | Check at runtime that a value of the given type cannot containt @big_map@ values bigMapAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoBigMap t) bigMapAbsense s = case checkBigMapPresence s of BigMapPresent -> Nothing BigMapAbsent -> Just Dict --- | Check at runtime that the given type does not contain nested 'TBigMap'+-- | Check at runtime that a value of the given type cannot contain nested @big_map@s. nestedBigMapsAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoNestedBigMaps t) nestedBigMapsAbsense s = case checkNestedBigMapsPresence s of NestedBigMapsPresent -> Nothing@@ -569,40 +681,49 @@ | BtHasBigMap | BtHasNestedBigMap | BtHasContract+ | BtHasTicket deriving stock (Show, Eq, Generic) deriving anyclass (NFData) instance Buildable BadTypeForScope where- build = \case+ build = buildRenderDoc++instance RenderDoc BadTypeForScope where+ renderDoc _ = \case BtNotComparable -> "is not comparable" BtIsOperation -> "has 'operation' type" BtHasBigMap -> "has 'big_map'" BtHasNestedBigMap -> "has nested 'big_map'" BtHasContract -> "has 'contract' type"+ BtHasTicket -> "has 'ticket' type" -- | Set of constraints that Michelson applies to parameters. -- -- Not just a type alias in order to be able to partially apply it-class (KnownT t, HasNoOp t, HasNoNestedBigMaps t) => ParameterScope t-instance (KnownT t, HasNoOp t, HasNoNestedBigMaps t) => ParameterScope t+class (SingI t, HasNoOp t, HasNoNestedBigMaps t) => ParameterScope t+instance (SingI t, HasNoOp t, HasNoNestedBigMaps t) => ParameterScope t -- | Set of constraints that Michelson applies to contract storage. -- -- Not just a type alias in order to be able to partially apply it-class (KnownT t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t) => StorageScope t-instance (KnownT t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t) => StorageScope t+class (SingI t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t) => StorageScope t+instance (SingI t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t) => StorageScope t -- | Set of constraints that Michelson applies to pushed constants. -- -- Not just a type alias in order to be able to partially apply it-class (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t) => ConstantScope t-instance (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t) => ConstantScope t+class (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t, HasNoTicket t) => ConstantScope t+instance (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t, HasNoTicket t) => ConstantScope t +-- | Alias for constraints which Michelson requires in @DUP@ instruction.+class (SingI t, HasNoTicket t) => DupableScope t+instance (SingI t, HasNoTicket t) => DupableScope t+ -- | Set of constraints that Michelson applies to packed values. -- -- Not just a type alias in order to be able to partially apply it-class (SingI t, HasNoOp t, HasNoBigMap t) => PackedValScope t-instance (SingI t, HasNoOp t, HasNoBigMap t) => PackedValScope t+class (SingI t, HasNoOp t, HasNoBigMap t, HasNoTicket t) => PackedValScope t+instance (SingI t, HasNoOp t, HasNoBigMap t, HasNoTicket t) => PackedValScope t -- | Set of constraints that Michelson applies to unpacked values. --@@ -633,34 +754,43 @@ checkScope = maybeToRight BtHasNestedBigMap $ nestedBigMapsAbsense sing instance SingI t => CheckScope (HasNoContract t) where checkScope = maybeToRight BtHasContract $ contractTypeAbsense sing+instance SingI t => CheckScope (HasNoTicket t) where+ checkScope = maybeToRight BtHasTicket $ ticketAbsense sing -instance KnownT t => CheckScope (ParameterScope t) where+instance SingI t => CheckScope (ParameterScope t) where checkScope = (\Dict Dict -> Dict) <$> checkScope @(HasNoOp t) <*> checkScope @(HasNoNestedBigMaps t) -instance KnownT t => CheckScope (StorageScope t) where+instance SingI t => CheckScope (StorageScope t) where checkScope = (\Dict Dict Dict -> Dict) <$> checkScope @(HasNoOp t) <*> checkScope @(HasNoNestedBigMaps t) <*> checkScope @(HasNoContract t) -instance KnownT t => CheckScope (ConstantScope t) where+instance SingI t => CheckScope (ConstantScope t) where checkScope =- (\Dict Dict Dict -> Dict)+ (\Dict Dict Dict Dict -> Dict) <$> checkScope @(HasNoOp t) <*> checkScope @(HasNoBigMap t) <*> checkScope @(HasNoContract t)+ <*> checkScope @(HasNoTicket t) -instance KnownT t => CheckScope (PackedValScope t) where+instance SingI t => CheckScope (DupableScope t) where checkScope =- (\Dict Dict -> Dict)+ (\Dict -> Dict)+ <$> checkScope @(HasNoTicket t)++instance SingI t => CheckScope (PackedValScope t) where+ checkScope =+ (\Dict Dict Dict -> Dict) <$> checkScope @(HasNoOp t) <*> checkScope @(HasNoBigMap t)+ <*> checkScope @(HasNoTicket t) -instance KnownT t => CheckScope (UnpackedValScope t) where+instance SingI t => CheckScope (UnpackedValScope t) where checkScope = (\Dict Dict -> Dict) <$> checkScope @(PackedValScope t)@@ -702,6 +832,9 @@ instance SingI a => WithDeMorganScope HasNoContract 'TPair a b where withDeMorganScope = mkWithDeMorgan @HasNoContract @a +instance SingI a => WithDeMorganScope HasNoTicket 'TPair a b where+ withDeMorganScope = mkWithDeMorgan @HasNoTicket @a+ instance SingI a => WithDeMorganScope HasNoBigMap 'TPair a b where withDeMorganScope = mkWithDeMorgan @HasNoBigMap @a @@ -714,6 +847,9 @@ instance SingI a => WithDeMorganScope HasNoContract 'TOr a b where withDeMorganScope = mkWithDeMorgan @HasNoContract @a +instance SingI a => WithDeMorganScope HasNoTicket 'TOr a b where+ withDeMorganScope = mkWithDeMorgan @HasNoTicket @a+ instance SingI a => WithDeMorganScope HasNoBigMap 'TOr a b where withDeMorganScope = mkWithDeMorgan @HasNoBigMap @a @@ -729,7 +865,7 @@ instance ( WithDeMorganScope HasNoOp t a b , WithDeMorganScope HasNoNestedBigMaps t a b- , KnownT a, KnownT b+ , SingI a, SingI b ) => WithDeMorganScope ParameterScope t a b where withDeMorganScope f = withDeMorganScope @HasNoOp @t @a @b $@@ -739,7 +875,7 @@ ( WithDeMorganScope HasNoOp t a b , WithDeMorganScope HasNoNestedBigMaps t a b , WithDeMorganScope HasNoContract t a b- , KnownT a, KnownT b+ , SingI a, SingI b ) => WithDeMorganScope StorageScope t a b where withDeMorganScope f = withDeMorganScope @HasNoOp @t @a @b $@@ -750,26 +886,30 @@ ( WithDeMorganScope HasNoOp t a b , WithDeMorganScope HasNoBigMap t a b , WithDeMorganScope HasNoContract t a b- , KnownT a, KnownT b+ , WithDeMorganScope HasNoTicket t a b+ , SingI a, SingI b ) => WithDeMorganScope ConstantScope t a b where withDeMorganScope f = withDeMorganScope @HasNoOp @t @a @b $ withDeMorganScope @HasNoBigMap @t @a @b $- withDeMorganScope @HasNoContract @t @a @b f+ withDeMorganScope @HasNoContract @t @a @b $+ withDeMorganScope @HasNoTicket @t @a @b f instance ( WithDeMorganScope HasNoOp t a b , WithDeMorganScope HasNoBigMap t a b- , KnownT a, KnownT b+ , WithDeMorganScope HasNoTicket t a b+ , SingI a, SingI b ) => WithDeMorganScope PackedValScope t a b where withDeMorganScope f = withDeMorganScope @HasNoOp @t @a @b $- withDeMorganScope @HasNoBigMap @t @a @b f+ withDeMorganScope @HasNoBigMap @t @a @b $+ withDeMorganScope @HasNoTicket @t @a @b f instance ( WithDeMorganScope PackedValScope t a b , WithDeMorganScope ConstantScope t a b- , KnownT a, KnownT b+ , SingI a, SingI b ) => WithDeMorganScope UnpackedValScope t a b where withDeMorganScope f = withDeMorganScope @PackedValScope @t @a @b $@@ -783,16 +923,19 @@ -} type ProperParameterBetterErrors t =- (KnownT t, ForbidOp t, ForbidNestedBigMaps t)+ (SingI t, ForbidOp t, ForbidNestedBigMaps t) type ProperStorageBetterErrors t =- (KnownT t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t)+ (SingI t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t) type ProperConstantBetterErrors t =- (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t)+ (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t, ForbidTicket t) +type ProperDupableBetterErrors t =+ (SingI t, ForbidTicket t)+ type ProperPackedValBetterErrors t =- (SingI t, ForbidOp t, ForbidBigMap t)+ (SingI t, ForbidOp t, ForbidBigMap t, ForbidTicket t) type ProperUnpackedValBetterErrors t = (ProperPackedValBetterErrors t, ProperConstantBetterErrors t)@@ -816,11 +959,17 @@ Dict \\ forbiddenOpEvi @t \\ forbiddenBigMapEvi @t \\ forbiddenContractTypeEvi @t+ \\ forbiddenTicketTypeEvi @t +properDupableEvi :: forall t. ProperDupableBetterErrors t :- DupableScope t+properDupableEvi = Sub $+ Dict \\ forbiddenTicketTypeEvi @t+ properPackedValEvi :: forall t. ProperPackedValBetterErrors t :- PackedValScope t properPackedValEvi = Sub $ Dict \\ forbiddenOpEvi @t \\ forbiddenBigMapEvi @t+ \\ forbiddenTicketTypeEvi @t properUnpackedValEvi :: forall t. ProperUnpackedValBetterErrors t :- UnpackedValScope t properUnpackedValEvi = Sub $
src/Michelson/Typed/Sing.hs view
@@ -2,6 +2,8 @@ -- -- SPDX-License-Identifier: LicenseRef-MIT-TQ +{-# LANGUAGE StandaloneKindSignatures #-}+{-# OPTIONS_GHC -Wno-unused-top-binds #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | Module, providing singleton boilerplate for@@ -14,224 +16,80 @@ module Michelson.Typed.Sing ( SingT (..)- , KnownT- , withSomeSingT- , fromSingT+ , castSingE+ , castM+ , eqP+ , requireEq ) where -import Data.Singletons (Sing, SingI(..), SingKind(..), SomeSing(..))+import Data.Type.Equality ((:~:)(..))+import Data.Singletons (Demote, KindOf, SingI(..), demote)+import Data.Singletons.TH (genSingletons, singDecideInstance)+import Data.Singletons.TH.Options (Options(..), defaultOptions, withOptions)+import Language.Haskell.TH (Name, mkName, nameBase) +import Fmt ((+||), (||+)) import Michelson.Typed.T (T(..))-+import Util.Sing (SingI1(..), castSing, eqI) --- | Instance of data family 'Sing' for 'T'.--- Custom instance is implemented in order to inject 'Typeable'--- constraint for some of constructors.-data SingT :: T -> Type where- STKey :: SingT 'TKey- STUnit :: SingT 'TUnit- STSignature :: SingT 'TSignature- STChainId :: SingT 'TChainId- STOption :: KnownT a => Sing a -> SingT ( 'TOption a)- STList :: KnownT a => Sing a -> SingT ( 'TList a )- STSet :: KnownT a => Sing a -> SingT ( 'TSet a )- STOperation :: SingT 'TOperation- STContract :: (KnownT a)- => Sing a -> SingT ( 'TContract a )- STPair :: (KnownT a, KnownT b)- => Sing a -> Sing b -> SingT ('TPair a b)- STOr :: (KnownT a, KnownT b)- => Sing a -> Sing b -> SingT ('TOr a b)- STLambda :: (KnownT a, KnownT b)- => Sing a -> Sing b -> SingT ('TLambda a b)- STMap :: (KnownT a, KnownT b)- => Sing a -> Sing b -> SingT ('TMap a b)- STBigMap :: (KnownT a, KnownT b)- => Sing a -> Sing b -> SingT ('TBigMap a b)- STInt :: SingT 'TInt- STNat :: SingT 'TNat- STString :: SingT 'TString- STBytes :: SingT 'TBytes- STMutez :: SingT 'TMutez- STBool :: SingT 'TBool- STKeyHash :: SingT 'TKeyHash- STBls12381Fr :: SingT 'TBls12381Fr- STBls12381G1 :: SingT 'TBls12381G1- STBls12381G2 :: SingT 'TBls12381G2- STTimestamp :: SingT 'TTimestamp- STAddress :: SingT 'TAddress- STNever :: SingT 'TNever+-- | 'SingI' and 'SDecide' instances for the 'T' kind.+$(let singPrefix, sPrefix :: Name -> Name+ singPrefix nm = mkName ("Sing" ++ nameBase nm)+ sPrefix nm = mkName ("S" ++ nameBase nm) in -type instance Sing = SingT+ withOptions defaultOptions{singledDataConName = sPrefix, singledDataTypeName = singPrefix} $+ concat <$> sequence [genSingletons [''T], singDecideInstance ''T]+ ) ------------------------------------------------ Singleton-related helpers for T+-- 'withSingI' usage -------------------------------------------- --- | 'Typeable' + 'SingI' constraints.------ This restricts a type to be a constructible type of 'T' kind.-class (Typeable t, SingI t) => KnownT (t :: T)-instance (Typeable t, SingI t) => KnownT t+-- | Previously, we were using 'SingI' constraints in 'SingT'+-- constructors. That was not so optimal because we have been+-- spending too much space at runtime. Instead of that, we process+-- values of 'SingT' using the function 'withSingI' in those places+-- where the 'SingI' constraint is required. 'withSingI' allows one+-- to create the 'SingI' context for a given 'Sing'. --- | Version of 'SomeSing' with 'Typeable' constraint,--- specialized for use with 'T' kind.-data SomeSingT where- SomeSingT :: forall (a :: T). (KnownT a)- => Sing a -> SomeSingT+---------------------------------------------+-- Singleton-related helpers for T+----------------------------------------------+instance SingI1 'TList where+ withSingI1 x = x --- | Version of 'withSomeSing' with 'Typeable' constraint--- provided to processing function.------ Required for not to erase these useful constraints when doing--- conversion from value of type 'T' to its singleton representation.-withSomeSingT- :: T- -> (forall (a :: T). (KnownT a) => Sing a -> r)- -> r-withSomeSingT t f = (\(SomeSingT s) -> f s) (toSingT t)+instance SingI k => SingI1 ('TMap k) where+ withSingI1 x = x --- | Version of 'fromSing' specialized for use with--- @data instance Sing :: T -> Type@ which requires 'Typeable'--- constraint for some of its constructors-fromSingT :: Sing (a :: T) -> T-fromSingT = \case- STKey -> TKey- STUnit -> TUnit- STSignature -> TSignature- STChainId -> TChainId- STOption t -> TOption (fromSingT t)- STList t -> TList (fromSingT t)- STSet t -> TSet (fromSingT t)- STOperation -> TOperation- STContract t -> TContract (fromSingT t)- STPair a b -> TPair (fromSingT a) (fromSingT b)- STOr a b -> TOr (fromSingT a) (fromSingT b)- STLambda a b -> TLambda (fromSingT a) (fromSingT b)- STMap a b -> TMap (fromSingT a) (fromSingT b)- STBigMap a b -> TBigMap (fromSingT a) (fromSingT b)- STInt -> TInt- STNat -> TNat- STString -> TString- STBytes -> TBytes- STMutez -> TMutez- STBool -> TBool- STKeyHash -> TKeyHash- STBls12381Fr -> TBls12381Fr- STBls12381G1 -> TBls12381G1- STBls12381G2 -> TBls12381G2- STTimestamp -> TTimestamp- STAddress -> TAddress- STNever -> TNever+castSingE+ :: forall (a :: T) (b :: T) t. (SingI a, SingI b)+ => t a -> Either Text (t b)+castSingE = maybeToRight errMsg . castSing+ where+ errMsg = "Type mismatch: expected " +|| demote @a ||++ ", got " +|| demote @b ||+ "" --- | Version of 'toSing' which creates 'SomeSingT'.-toSingT :: T -> SomeSingT-toSingT = \case- TKey -> SomeSingT STKey- TUnit -> SomeSingT STUnit- TSignature -> SomeSingT STSignature- TChainId -> SomeSingT STChainId- TOption t -> withSomeSingT t $ \tSing -> SomeSingT $ STOption tSing- TList t -> withSomeSingT t $ \tSing -> SomeSingT $ STList tSing- TSet ct -> withSomeSingT ct $ \ctSing -> SomeSingT $ STSet ctSing- TOperation -> SomeSingT STOperation- TContract t -> withSomeSingT t $ \tSing -> SomeSingT $ STContract tSing- TPair l r ->- withSomeSingT l $ \lSing ->- withSomeSingT r $ \rSing ->- SomeSingT $ STPair lSing rSing- TOr l r ->- withSomeSingT l $ \lSing ->- withSomeSingT r $ \rSing ->- SomeSingT $ STOr lSing rSing- TLambda l r ->- withSomeSingT l $ \lSing ->- withSomeSingT r $ \rSing ->- SomeSingT $ STLambda lSing rSing- TMap l r ->- withSomeSingT l $ \lSing ->- withSomeSingT r $ \rSing ->- SomeSingT $ STMap lSing rSing- TBigMap l r ->- withSomeSingT l $ \lSing ->- withSomeSingT r $ \rSing ->- SomeSingT $ STBigMap lSing rSing- TInt -> SomeSingT STInt- TNat -> SomeSingT STNat- TString -> SomeSingT STString- TBytes -> SomeSingT STBytes- TMutez -> SomeSingT STMutez- TBool -> SomeSingT STBool- TKeyHash -> SomeSingT STKeyHash- TBls12381Fr -> SomeSingT STBls12381Fr- TBls12381G1 -> SomeSingT STBls12381G1- TBls12381G2 -> SomeSingT STBls12381G2- TTimestamp -> SomeSingT STTimestamp- TAddress -> SomeSingT STAddress- TNever -> SomeSingT STNever+-- | Monadic version of 'castSing'.+-- Throws an error using the given function if the cast fails.+castM+ :: forall (a :: T) (b :: T) t m. (SingI a, SingI b, Monad m)+ => t a+ -> (forall x. Demote (KindOf a) -> Demote (KindOf b) -> m x)+ -> m (t b)+castM a throwErr =+ requireEq @a @b throwErr <&> \Refl -> a -instance SingKind T where- type Demote T = T- fromSing = fromSingT- toSing t = case toSingT t of SomeSingT s -> SomeSing s+-- | Monadic version of 'eqI'.+-- Throws an error using the given function if the two types are not equal.+requireEq+ :: forall (a :: T) (b :: T) m. (SingI a, SingI b, Monad m)+ => (forall x. Demote (KindOf a) -> Demote (KindOf b) -> m x)+ -> m (a :~: b)+requireEq throwErr =+ case eqI @a @b of+ Just p -> pure p+ Nothing -> throwErr (demote @a) (demote @b) -instance SingI 'TKey where- sing = STKey-instance SingI 'TUnit where- sing = STUnit-instance SingI 'TSignature where- sing = STSignature-instance SingI 'TChainId where- sing = STChainId-instance SingI 'TNever where- sing = STNever-instance (KnownT a) => SingI ( 'TOption (a :: T)) where- sing = STOption sing-instance (KnownT a) => SingI ( 'TList (a :: T)) where- sing = STList sing-instance (KnownT a) => SingI ( 'TSet (a :: T)) where- sing = STSet sing-instance SingI 'TOperation where- sing = STOperation-instance (KnownT a) =>- SingI ( 'TContract (a :: T)) where- sing = STContract sing-instance (KnownT a, KnownT b) =>- SingI ( 'TPair a b) where- sing = STPair sing sing-instance (KnownT a, KnownT b) =>- SingI ( 'TOr a b) where- sing = STOr sing sing-instance (KnownT a, KnownT b) =>- SingI ( 'TLambda a b) where- sing = STLambda sing sing-instance (KnownT a, KnownT b) =>- SingI ( 'TMap a b) where- sing = STMap sing sing-instance (KnownT a, KnownT b) =>- SingI ( 'TBigMap a b) where- sing = STBigMap sing sing-instance SingI 'TInt where- sing = STInt-instance SingI 'TNat where- sing = STNat-instance SingI 'TString where- sing = STString-instance SingI 'TBytes where- sing = STBytes-instance SingI 'TMutez where- sing = STMutez-instance SingI 'TBool where- sing = STBool-instance SingI 'TKeyHash where- sing = STKeyHash-instance SingI 'TBls12381Fr where- sing = STBls12381Fr-instance SingI 'TBls12381G1 where- sing = STBls12381G1-instance SingI 'TBls12381G2 where- sing = STBls12381G2-instance SingI 'TTimestamp where- sing = STTimestamp-instance SingI 'TAddress where- sing = STAddress+-- | Version of 'eqI' that uses 'Proxy'+eqP :: forall (a :: T) (b :: T). (SingI a, SingI b) => Proxy a -> Proxy b -> Maybe (a :~: b)+eqP _ _ = eqI @a @b
src/Michelson/Typed/T.hs view
@@ -13,6 +13,7 @@ import Fmt (Buildable(..), Builder, listF) import qualified Michelson.Untyped.Annotation as Un import qualified Michelson.Untyped.Type as Un+import Michelson.Printer.Util (RenderDoc (..)) -- | Michelson language type with annotations stripped off. data T =@@ -25,6 +26,7 @@ | TSet T | TOperation | TContract T+ | TTicket T | TPair T T | TOr T T | TLambda T T@@ -74,6 +76,7 @@ convert (TSet a) = Un.TSet $ Un.Ty (Un.unwrapT $ toUType a) Un.noAnn convert (TOperation) = Un.TOperation convert (TContract a) = Un.TContract (toUType a)+ convert (TTicket a) = Un.TTicket (toUType a) convert (TPair a b) = Un.TPair Un.noAnn Un.noAnn Un.noAnn Un.noAnn (toUType a) (toUType b) convert (TOr a b) =@@ -87,6 +90,9 @@ instance Buildable T where build = build . toUType++instance RenderDoc T where+ renderDoc context = renderDoc context . toUType -- | Format type stack in a pretty way. buildStack :: [T] -> Builder
src/Michelson/Typed/Util.hs view
@@ -17,9 +17,10 @@ , linearizeLeftDeep -- * Value analysis- , dfsValue- , dfsFoldValue- , dfsModifyValue+ , dfsFoldMapValue+ , dfsFoldMapValueM+ , dfsMapValue+ , dfsTraverseValue , isStringValue , isBytesValue , allAtomicValues@@ -31,9 +32,9 @@ import Prelude hiding (Ordering(..)) +import Control.Monad.Writer.Strict (execWriterT, runWriter, tell, writer) import Data.Constraint (Dict(..)) import Data.Default (Default(..))-import qualified Data.Foldable as F import qualified Data.Map as M import qualified Data.Set as S import qualified Text.Show@@ -105,6 +106,7 @@ FrameInstr p i1 -> recursion1 (FrameInstr p) i1 Nested i1 -> recursion1 Nested i1 DocGroup dg i1 -> recursion1 (DocGroup dg) i1+ Fn t sfn i1 -> recursion1 (Fn t sfn) i1 IF_NONE i1 i2 -> recursion2 IF_NONE i1 i2 IF_LEFT i1 i2 -> recursion2 IF_LEFT i1 i2 IF_CONS i1 i2 -> recursion2 IF_CONS i1 i2@@ -129,13 +131,13 @@ VLam lambda -> bimap (VLam . analyzeInstrFailure) Just $ dfsInstr settings step (rfAnyInstr lambda) otherV -> (otherV, Nothing)- -- Note that @dfsValue@ does not respect 'CtorEffectsApp',+ -- Note that @dfsTraverseValue@ does not respect 'CtorEffectsApp', -- so if we encounter a value that contains more than one lambda -- this function may misbehave. -- That's very unlikely in practice.- -- In #264 we will support this feature in @dfsValue@.+ -- In #264 we will support this feature in @dfsTraverseValue@. let- (innerV, innerXMaybe) = dfsValue valueStep v+ (innerV, innerXMaybe) = runWriter $ dfsTraverseValue (writer . valueStep) v innerX <- innerXMaybe let (outerI, outerX) = step $ PUSH innerV@@ -168,6 +170,7 @@ NONE{} -> step i UNIT{} -> step i AnnPAIR{} -> step i+ AnnUNPAIR{} -> step i PAIRN{} -> step i UNPAIRN{} -> step i AnnLEFT{} -> step i@@ -240,6 +243,10 @@ LEVEL{} -> step i SELF_ADDRESS{} -> step i NEVER{} -> step i+ TICKET{} -> step i+ READ_TICKET{} -> step i+ SPLIT_TICKET{} -> step i+ JOIN_TICKETS{} -> step i where recursion1 :: forall a b c d. (Instr a b -> Instr c d) -> Instr a b -> (Instr c d, x)@@ -328,6 +335,7 @@ Ext e -> RfNormal (Ext e) Nested i -> Nested `rfMapAnyInstr` go i DocGroup g i -> DocGroup g `rfMapAnyInstr` go i+ Fn t sfn i -> Fn t sfn `rfMapAnyInstr` go i IF_NONE l r -> rfMerge IF_NONE (go l) (go r) IF_LEFT l r -> rfMerge IF_LEFT (go l) (go r)@@ -356,6 +364,7 @@ i@NONE{} -> RfNormal i i@UNIT{} -> RfNormal i i@AnnPAIR{} -> RfNormal i+ i@AnnUNPAIR{} -> RfNormal i i@PAIRN{} -> RfNormal i i@UNPAIRN{} -> RfNormal i i@AnnLEFT{} -> RfNormal i@@ -429,6 +438,10 @@ i@LEVEL -> RfNormal i i@SELF_ADDRESS -> RfNormal i NEVER -> RfAlwaysFails NEVER+ i@TICKET -> RfNormal i+ i@READ_TICKET -> RfNormal i+ i@SPLIT_TICKET -> RfNormal i+ i@JOIN_TICKETS -> RfNormal i -- | There are many ways to represent a sequence of more than 2 instructions. -- E. g. for @i1; i2; i3@ it can be @Seq i1 $ Seq i2 i3@ or @Seq (Seq i1 i2) i3@.@@ -470,13 +483,21 @@ ---------------------------------------------------------------------------- -- | Traverse a value in depth-first order.-dfsValue ::- forall t x.- Monoid x- => (forall t'. Value t' -> (Value t', x))+dfsMapValue ::+ forall t.+ (forall t'. Value t' -> Value t') -> Value t- -> (Value t, x)-dfsValue step i = case i of+ -> Value t+dfsMapValue step v = runIdentity $ dfsTraverseValue (pure . step) v++-- | Traverse a value in depth-first order.+dfsTraverseValue ::+ forall t m.+ (Monad m)+ => (forall t'. Value t' -> m (Value t'))+ -> Value t+ -> m (Value t)+dfsTraverseValue step i = case i of -- Atomic VKey{} -> step i VUnit -> step i@@ -484,6 +505,7 @@ VChainId{} -> step i VOp{} -> step i VContract{} -> step i+ VTicket{} -> step i -- cannot appear as constant in a contract VLam{} -> step i VInt{} -> step i VNat{} -> step i@@ -502,81 +524,70 @@ VOption mVal -> case mVal of Nothing -> step i Just val -> recursion1 (VOption . Just) val- VList vals ->- let- (vs, xs) = unzip $ map (dfsValue step) vals- (v, x) = step $ VList vs- in- (v, x <> F.fold xs)- VSet vals ->- let- (cs, cxs) =- S.foldr (\a (s, xs) -> let (c, x) = step a in (S.insert c s, x <> xs))- (S.empty, mempty) vals- (v, vx) = step (VSet cs)- in (v, vx <> cxs)- VPair (v1, v2) -> recursion2 (curry VPair) v1 v2+ VList vals -> do+ vs <- traverse (dfsTraverseValue step) vals+ step $ VList vs+ VSet vals -> do+ cs <- S.fromList <$> traverse (dfsTraverseValue step) (S.toList vals)+ step (VSet cs)+ VPair (v1, v2) -> do+ v1' <- dfsTraverseValue step v1+ v2' <- dfsTraverseValue step v2+ step $ VPair (v1', v2') VOr vEither -> case vEither of Left v -> recursion1 (VOr . Left) v Right v -> recursion1 (VOr . Right) v VMap vmap -> mapRecursion VMap vmap- VBigMap vmap -> mapRecursion VBigMap vmap+ VBigMap bmId vmap -> mapRecursion (VBigMap bmId) vmap where recursion1 :: forall t'. (Value t' -> Value t) -> Value t'- -> (Value t, x)- recursion1 constructor i' =- let- (v, x) = dfsValue step i'- (v', x') = step $ constructor v- in- (v', x <> x')- recursion2 ::- forall t1 t2.- (Value t1 -> Value t2 -> Value t)- -> Value t1- -> Value t2- -> (Value t, x)- recursion2 constructor i1 i2 =- let- (v1, x1) = dfsValue step i1- (v2, x2) = dfsValue step i2- (v, x) = step $ constructor v1 v2- in- (v, x1 <> x2 <> x)+ -> m (Value t)+ recursion1 constructor v = do+ v' <- dfsTraverseValue step v+ step $ constructor v' mapRecursion- :: forall t' k. Comparable k- => (M.Map (Value k) (Value t') -> Value t)- -> M.Map (Value k) (Value t')- -> (Value t, x)- mapRecursion constructor vmap =- let- (ms, cxs) = M.foldrWithKey (\k a (m, xs) ->- let (c, cx) = step k- (v, vx) = dfsValue step a- in (M.insert c v m, vx <> cx <> xs)) (M.empty, mempty) vmap- (v', x') = step $ constructor ms- in- (v', cxs <> x')+ :: forall k v. Comparable k+ => (M.Map (Value k) (Value v) -> Value t)+ -> M.Map (Value k) (Value v)+ -> m (Value t)+ mapRecursion constructor vmap = do+ vmap' <-+ M.fromList <$> forM (M.toList vmap) \(k, v) -> do+ k' <- dfsTraverseValue step k+ v' <- dfsTraverseValue step v+ pure (k', v')+ step $ constructor vmap' --- | Specialization of 'dfsValue' for case when changing the value is+-- | Specialization of 'dfsMapValue' for case when changing the value is -- not required.-dfsFoldValue ::+dfsFoldMapValue :: Monoid x => (forall t'. Value t' -> x) -> Value t -> x-dfsFoldValue f = snd . dfsValue (\v -> (v, f v))+dfsFoldMapValue step v =+ runIdentity $ dfsFoldMapValueM (pure . step) v --- | Specialization of 'dfsValue' which only modifies given value.-dfsModifyValue ::- (forall t'. Value t' -> Value t')- -> Value t+-- | Specialization of 'dfsMapValue' for case when changing the value is+-- not required.+dfsFoldMapValueM+ :: (Monoid x, Monad m)+ => (forall t'. Value t' -> m x) -> Value t-dfsModifyValue f = fst . dfsValue ((, ()) . f)+ -> m x+dfsFoldMapValueM step v = do+ execWriterT $+ dfsTraverseValue+ (\val -> do+ x <- lift $ step val+ tell x+ pure val+ )+ v -- | If value is a string, return the stored string. isStringValue :: Value t -> Maybe MText@@ -597,7 +608,7 @@ -- values in a list. allAtomicValues :: forall t a. (forall t'. Value t' -> Maybe a) -> Value t -> [a]-allAtomicValues selector = dfsFoldValue (maybeToList . selector)+allAtomicValues selector = dfsFoldMapValue (maybeToList . selector) --------------------------------------------------------------------------------@@ -630,18 +641,19 @@ => Instr s (st ': s) -> PushableStorageSplit s st - -- | The type of the storage and part of its value (here @bms@) contain one or- -- more @big_map@s. The instruction can take the non-pushable 'Value bms' and- -- reconstruct the original 'Value st' without using any 'EMPTY_BIG_MAP'.+ -- | The type of the storage and part of its value (here @heavy@) contain one or+ -- more @big_map@s or @ticket@s. The instruction can take the non-pushable+ -- 'Value heavy' and reconstruct the original 'Value st' without using any+ -- 'EMPTY_BIG_MAP'. PartlyPushableStorage- :: (StorageScope bms, StorageScope st)- => Value bms -> Instr (bms ': s) (st ': s)+ :: (StorageScope heavy, StorageScope st)+ => Value heavy -> Instr (heavy ': s) (st ': s) -> PushableStorageSplit s st -- | Splits the given storage 'Value' into a 'PushableStorageSplit'. -- -- This is based off the fact that the only storages that cannot be directly--- 'PUSH'ed are the ones that contain 'BigMap's.+-- 'PUSH'ed are the ones that contain 'BigMap's and tickets. -- See difference between 'StorageScope' and 'ConstantScope'. -- -- So what we do here is to create a 'Value' as small as possible with all the@@ -670,9 +682,10 @@ VBls12381G2{} -> ConstantStorage v VTimestamp{} -> ConstantStorage v VAddress{} -> ConstantStorage v+ VTicket{} -> PartlyPushableStorage v Nop -- Non-atomic- VOption (Nothing :: Maybe (Value tm)) -> case checkScope @(HasNoBigMap tm) of+ VOption (Nothing :: Maybe (Value tm)) -> case checkScope @(ConstantScope tm) of Right Dict -> ConstantStorage $ VOption Nothing Left _ -> PushableValueStorage $ NONE VOption (Just jVal :: Maybe (Value tm)) -> case splitPushableStorage jVal of@@ -680,7 +693,7 @@ PushableValueStorage instr -> PushableValueStorage $ instr `Seq` SOME PartlyPushableStorage val instr -> PartlyPushableStorage val $ instr `Seq` SOME - VList (vals :: [Value tl]) -> case checkScope @(HasNoBigMap tl) of+ VList (vals :: [Value tl]) -> case checkScope @(ConstantScope tl) of Right Dict -> ConstantStorage v Left _ -> -- Here we check that even tho the type contains big_maps, we actually@@ -730,7 +743,7 @@ VOr (Left orVal :: Either (Value t1) (Value t2)) -> withValueTypeSanity orVal $ withDeMorganScope @StorageScope @'T.TOr @t1 @t2 $ case splitPushableStorage orVal of- ConstantStorage val -> case checkScope @(HasNoBigMap t2) of+ ConstantStorage val -> case checkScope @(ConstantScope t2) of -- note: here we need to check for the opposite branch too Right Dict -> ConstantStorage v Left _ -> PushableValueStorage $ PUSH val `Seq` LEFT@@ -739,7 +752,7 @@ VOr (Right orVal :: Either (Value t1) (Value t2)) -> withValueTypeSanity orVal $ withDeMorganScope @StorageScope @'T.TOr @t1 @t2 $ case splitPushableStorage orVal of- ConstantStorage val -> case checkScope @(HasNoBigMap t1) of+ ConstantStorage val -> case checkScope @(ConstantScope t1) of -- note: here we need to check for the opposite branch too Right Dict -> ConstantStorage v Left _ -> PushableValueStorage $ PUSH val `Seq` RIGHT@@ -754,7 +767,7 @@ -- enforced in the type system as well, but it may have more -- downsides than it's worth accepting. error "impossible: all map keys should be PUSHable"- Right Dict -> case checkScope @(HasNoBigMap tv) of+ Right Dict -> case checkScope @(ConstantScope tv) of Right Dict -> ConstantStorage v _ -> withDeMorganScope @HasNoOp @'T.TMap @tk @tv $ -- Similarly as for lists, here we check that even tho the value type@@ -771,4 +784,4 @@ in maybe (PartlyPushableStorage v Nop) PushableValueStorage $ foldM handleMap EMPTY_MAP $ M.toList vMap - VBigMap _ -> PartlyPushableStorage v Nop+ VBigMap _ _ -> PartlyPushableStorage v Nop
src/Michelson/Typed/Value.hs view
@@ -7,9 +7,7 @@ -- | Module, containing data types for Michelson value. module Michelson.Typed.Value- ( SomeValue' (..)- , SomeConstrainedValue' (..)- , Comparability (..)+ ( Comparability (..) , Comparable , ComparabilityScope , ContractInp1@@ -38,21 +36,21 @@ ) where import Data.Constraint (Dict(..), (\\))-import Data.Singletons (Sing, SingI(..))+import Data.Singletons (Sing) 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.Scope (BadTypeForScope(..), CheckScope(..), ParameterScope, StorageScope)+import Michelson.Typed.Scope import Michelson.Typed.Sing import Michelson.Typed.T (T(..)) import Tezos.Address (Address) import Tezos.Core (ChainId, Mutez, Timestamp) import Tezos.Crypto (Bls12381Fr, Bls12381G1, Bls12381G2, KeyHash, PublicKey, Signature)+import Util.Sing (eqParamSing, eqParamSing3) import Util.TH-import Util.Typeable -- | Data type, representing operation, list of which is returned -- by Michelson contract (according to calling convention).@@ -82,11 +80,11 @@ instance Eq (Operation' instr) where op1 == op2 = case (op1, op2) of- (OpTransferTokens tt1, OpTransferTokens tt2) -> eqParam1 tt1 tt2+ (OpTransferTokens tt1, OpTransferTokens tt2) -> tt1 `eqParamSing` tt2 (OpTransferTokens _, _) -> False (OpSetDelegate sd1, OpSetDelegate sd2) -> sd1 == sd2 (OpSetDelegate _, _) -> False- (OpCreateContract cc1, OpCreateContract cc2) -> eqParam3 cc1 cc2+ (OpCreateContract cc1, OpCreateContract cc2) -> cc1 `eqParamSing3` cc2 (OpCreateContract _, _) -> False data TransferTokens instr p = TransferTokens@@ -200,6 +198,7 @@ IsComparable ('TSet _) = 'False IsComparable 'TOperation = 'False IsComparable ('TContract _) = 'False+ IsComparable ('TTicket _) = 'False IsComparable ('TOr a b) = IsComparable a && IsComparable b IsComparable ('TLambda _ _) = 'False IsComparable ('TMap _ _) = 'False@@ -255,7 +254,7 @@ -- | Alias for comparable types. type ComparabilityScope t =- (KnownT t, Comparable t)+ (SingI t, Comparable t) data Comparability t where CanBeCompared :: (Comparable t) => Comparability t@@ -278,6 +277,7 @@ STSet _ -> CannotBeCompared STOperation -> CannotBeCompared STContract _ -> CannotBeCompared+ STTicket _ -> CannotBeCompared STLambda _ _ -> CannotBeCompared STMap _ _ -> CannotBeCompared STBigMap _ _ -> CannotBeCompared@@ -307,7 +307,7 @@ instance SingI t => CheckScope (Comparable t) where checkScope = maybeToRight BtNotComparable $ comparabilityPresence sing -instance (KnownT t) => CheckScope (ComparabilityScope t) where+instance (SingI t) => CheckScope (ComparabilityScope t) where checkScope = (\Dict -> Dict) <$> checkScope @(Comparable t) @@ -323,31 +323,36 @@ VChainId :: ChainId -> Value' instr 'TChainId VOption :: forall t instr.- (KnownT t)+ (SingI t) => Maybe (Value' instr t) -> Value' instr ('TOption t) VList :: forall t instr.- (KnownT t)+ (SingI t) => [Value' instr t] -> Value' instr ('TList t) VSet :: forall t instr.- (KnownT t, Comparable t)+ (SingI t, Comparable t) => Set (Value' instr t) -> Value' instr ('TSet t) VOp :: Operation' instr -> Value' instr 'TOperation VContract :: forall arg instr.- Address -> SomeEntrypointCallT arg -> Value' instr ('TContract arg)+ (SingI arg, HasNoOp arg)+ => Address -> SomeEntrypointCallT arg -> Value' instr ('TContract arg)+ VTicket+ :: forall arg instr.+ (Comparable arg)+ => Address -> Value' instr arg -> Natural -> Value' instr ('TTicket arg) VPair :: forall l r instr. (Value' instr l, Value' instr r) -> Value' instr ('TPair l r) VOr :: forall l r instr.- (KnownT l, KnownT r)+ (SingI l, SingI r) => Either (Value' instr l) (Value' instr r) -> Value' instr ('TOr l r) VLam :: forall inp out instr.- ( KnownT inp, KnownT out+ ( SingI inp, SingI out , forall i o. Show (instr i o) , forall i o. Eq (instr i o) , forall i o. NFData (instr i o)@@ -355,12 +360,14 @@ => RemFail instr (inp ': '[]) (out ': '[]) -> Value' instr ('TLambda inp out) VMap :: forall k v instr.- (KnownT k, KnownT v, Comparable k)+ (SingI k, SingI v, Comparable k) => Map (Value' instr k) (Value' instr v) -> Value' instr ('TMap k v) VBigMap :: forall k v instr.- (KnownT k, KnownT v, Comparable k)- => Map (Value' instr k) (Value' instr v) -> Value' instr ('TBigMap k v)+ (SingI k, SingI v, Comparable k, HasNoBigMap v)+ => Maybe Natural -- ^ The big_map's ID. This is only used in the interpreter.+ -> Map (Value' instr k) (Value' instr v)+ -> Value' instr ('TBigMap k v) VInt :: Integer -> Value' instr 'TInt VNat :: Natural -> Value' instr 'TNat VString :: MText -> Value' instr 'TString@@ -389,28 +396,6 @@ buildVContract = \case VContract addr epc -> "Contract " +| addr |+ " call " +| epc |+ "" -data SomeValue' instr where- SomeValue :: KnownT t => Value' instr t -> SomeValue' instr--deriving stock instance Show (SomeValue' instr)--instance Eq (SomeValue' instr) where- SomeValue v1 == SomeValue v2 = v1 `eqParam1` v2--data SomeConstrainedValue' instr (c :: T -> Constraint) where- SomeConstrainedValue- :: forall (t :: T) (c :: T -> Constraint) instr- . (c t)- => Value' instr t- -> SomeConstrainedValue' instr c--deriving stock instance Show (SomeConstrainedValue' instr c)---- TODO--- @gromak: perhaps we should implement `SomeValue'` in terms of--- `SomeConstrainedValue'`, but it will require changing quite a lot of code,--- so it is postponed.- -- | Turn 'EpLiftSequence' into actual function on 'Value's. compileEpLiftSequence :: EpLiftSequence arg param@@ -437,7 +422,7 @@ -- type family Any :: T where -- -- nothing here -- @-valueTypeSanity :: Value' instr t -> Dict (KnownT t)+valueTypeSanity :: Value' instr t -> Dict (SingI t) valueTypeSanity = \case VKey{} -> Dict VUnit{} -> Dict@@ -448,6 +433,8 @@ VSet{} -> Dict VOp{} -> Dict VContract _ (SomeEpc EntrypointCall{}) -> Dict+ VTicket _ v _ -> case valueTypeSanity v of+ Dict -> Dict VPair (l, r) -> case (valueTypeSanity l, valueTypeSanity r) of (Dict, Dict) -> Dict VOr{} -> Dict@@ -468,14 +455,14 @@ VAddress{} -> Dict -- | Provide a witness of that value's type is known.-withValueTypeSanity :: Value' instr t -> (KnownT t => a) -> a+withValueTypeSanity :: Value' instr t -> (SingI t => a) -> a withValueTypeSanity v a = case valueTypeSanity v of Dict -> a -- | Extended values comparison - it does not require 'Value's to be -- of the same type, only their content to match. eqValueExt :: Value' instr t1 -> Value' instr t2 -> Bool eqValueExt v1 v2 =- v1 `eqParam1` v2+ v1 `eqParamSing` v2 \\ valueTypeSanity v1 \\ valueTypeSanity v2
src/Michelson/Untyped/Annotation.hs view
@@ -11,13 +11,17 @@ , pattern WithAnn -- * Annotation Set- , AnnotationSet+ , AnnotationSet(..)+ , annsCount , emptyAnnSet+ , firstAnn , fullAnnSet , isNoAnnSet , minAnnSetSize+ , secondAnn , singleAnnSet , singleGroupAnnSet+ , minimizeAnnSet -- * Rendering , KnownAnnTag(..)@@ -36,7 +40,7 @@ , varAnnQ , fieldAnnQ , typeAnnQ- , mkAnnotationUnsafe+ , unsafeMkAnnotation , mkAnnotation , specialVarAnns , specialFieldAnn@@ -58,11 +62,11 @@ import Data.Typeable (eqT, (:~:)(..)) import Fmt (Buildable(build)) import Instances.TH.Lift ()+import qualified Language.Haskell.TH as TH import Language.Haskell.TH.Lift (deriveLift)+import qualified Language.Haskell.TH.Quote as TH import Text.PrettyPrint.Leijen.Text (Doc, hsep, textStrict, (<+>)) import qualified Text.Show-import qualified Language.Haskell.TH as TH-import qualified Language.Haskell.TH.Quote as TH import Michelson.Printer.Util (RenderDoc(..), buildRenderDoc, doesntNeedParens, printDocS) import Util.Aeson@@ -73,13 +77,13 @@ -- (except for the first character, here parametrized in the type `tag`) the -- allowed character set is the one matching the following regexp: -- @%|@%%|%@|[@:%][_0-9a-zA-Z][_0-9a-zA-Z\.%@]*-newtype Annotation tag = AnnotationUnsafe { unAnnotation :: Text }+newtype Annotation tag = UnsafeAnnotation { unAnnotation :: Text } deriving stock (Eq, Data, Functor, Generic) instance NFData (Annotation tag) pattern Annotation :: Text -> Annotation tag-pattern Annotation ann <- AnnotationUnsafe ann+pattern Annotation ann <- UnsafeAnnotation ann {-# COMPLETE Annotation :: Annotation #-} @@ -169,6 +173,34 @@ trimEndNoAnn :: [Annotation tag] -> [Annotation tag] trimEndNoAnn = foldr (\a lst -> if null lst && a == noAnn then [] else a : lst) [] +-- | Returns the number of annotations in 'AnnotationSet' for each type.+annsCount :: AnnotationSet -> (Int, Int, Int)+annsCount (AnnotationSet tas fas vas) = (length tas, length fas, length vas)++-- | Returns the first annotation in a list of annotations of a specific type+-- in 'AnnotationSet', or 'noAnn' if this list is empty.+firstAnn :: (KnownAnnTag tag) => AnnotationSet -> Annotation tag+firstAnn = getAnn (\case [] -> noAnn; a : _ -> a)++-- | Returns the second annotation in a list of annotations of a specific type+-- in 'AnnotationSet', or 'noAnn' if this list contains less than 2 elements.+secondAnn :: (KnownAnnTag tag) => AnnotationSet -> Annotation tag+secondAnn = getAnn (\case [] -> noAnn; [_] -> noAnn; _ : a : _ -> a)++-- | Retrieves an annotation of a specific type from 'AnnotationSet' using+-- the passed function.+getAnn :: forall tag. (KnownAnnTag tag)+ => ([Annotation tag] -> Annotation tag)+ -> AnnotationSet+ -> Annotation tag+getAnn getter annSet = case eqT @tag @TypeTag of+ Just Refl -> getter $ asTypes annSet+ Nothing -> case eqT @tag @FieldTag of+ Just Refl -> getter $ asFields annSet+ Nothing -> case eqT @tag @VarTag of+ Just Refl -> getter $ asVars annSet+ Nothing -> error "Impossible"+ -------------------------------------------------------------------------------- -- Rendering --------------------------------------------------------------------------------@@ -232,26 +264,26 @@ -------------------------------------------------------------------------------- noAnn :: Annotation a-noAnn = AnnotationUnsafe ""+noAnn = UnsafeAnnotation "" -- | Makes an `Annotation` from its textual value, prefix (%/@/:) excluded -- Throws an error if the given `Text` contains invalid characters-mkAnnotationUnsafe :: HasCallStack => Text -> Annotation a-mkAnnotationUnsafe = either error id . mkAnnotation+unsafeMkAnnotation :: HasCallStack => Text -> Annotation a+unsafeMkAnnotation = either error id . mkAnnotation -- | Makes an `Annotation` from its textual value, prefix (%/@/:) excluded -- Returns a `Text` error message if the given `Text` contains invalid characters mkAnnotation :: Text -> Either Text (Annotation a) mkAnnotation text -- TODO [#48] these are special annotations and should not be always allowed- | text `elem` specialVarAnns = Right $ AnnotationUnsafe text- | text == specialFieldAnn = Right $ AnnotationUnsafe text+ | text `elem` specialVarAnns = Right $ UnsafeAnnotation text+ | text == specialFieldAnn = Right $ UnsafeAnnotation text | otherwise = do suffix <- case T.uncons text of Just (h, tl) | isValidAnnStart h -> Right tl Just (h, _) -> Left $ "Invalid first character: '" <> one h <> "'" _ -> Right ""- maybe (Right $ AnnotationUnsafe text) (\c -> Left $ "Invalid character: '" <> one c <> "'") $+ maybe (Right $ UnsafeAnnotation text) (\c -> Left $ "Invalid character: '" <> one c <> "'") $ T.find (not . isValidAnnBodyChar) suffix -- |@@ -289,14 +321,14 @@ case (mkAnnotation $ toText @String s) of Left err -> fail $ toString err Right _ -> case annTypeMb of- Nothing -> [e| (AnnotationUnsafe s) |]- Just annType -> [e| (AnnotationUnsafe s :: $(annType)) |]+ Nothing -> [e| (UnsafeAnnotation s) |]+ Just annType -> [e| (UnsafeAnnotation s :: $(annType)) |] , TH.quotePat = \s -> case (mkAnnotation $ toText @String s) of Left err -> fail $ toString err Right _ -> case annTypeMb of- Nothing -> [p| AnnotationUnsafe $(TH.litP $ TH.StringL s) |]- Just annType -> [p| (AnnotationUnsafe $(TH.litP $ TH.StringL s) :: $(annType)) |]+ Nothing -> [p| UnsafeAnnotation $(TH.litP $ TH.StringL s) |]+ Just annType -> [p| (UnsafeAnnotation $(TH.litP $ TH.StringL s) :: $(annType)) |] , TH.quoteType = \_ -> fail "Cannot use this QuasiQuoter at type position" , TH.quoteDec = \_ -> fail "Cannot use this QuasiQuoter at declaration position" }@@ -332,8 +364,8 @@ instance Semigroup VarAnn where Annotation a <> Annotation b- | a == "" || b == "" = AnnotationUnsafe $ a <> b- | otherwise = AnnotationUnsafe $ a <> "." <> b+ | a == "" || b == "" = UnsafeAnnotation $ a <> b+ | otherwise = UnsafeAnnotation $ a <> "." <> b instance Monoid VarAnn where mempty = noAnn@@ -387,7 +419,7 @@ ifAnnUnified a1 a2 = isJust $ a1 `unifyAnn` a2 convAnn :: Annotation tag1 -> Annotation tag2-convAnn (Annotation a) = AnnotationUnsafe a+convAnn (Annotation a) = UnsafeAnnotation a pattern WithAnn :: Annotation tag -> Annotation tag pattern WithAnn ann <- ann@(Annotation (toString -> _:_))
src/Michelson/Untyped/Entrypoints.hs view
@@ -19,10 +19,12 @@ import Data.Aeson.TH (deriveJSON) import qualified Data.Map as Map-import Fmt (Buildable(..), pretty, (+|), (|+))+import Fmt (Buildable(..), pretty) import Michelson.Untyped.Annotation import Michelson.Untyped.Type+import Michelson.Printer.Util (RenderDoc (..), renderAnyBuildable, buildRenderDoc)+import Text.PrettyPrint.Leijen.Text ((<+>), enclose) import Util.Aeson import Util.CLI @@ -53,7 +55,7 @@ -- code. There is an -- [issue](https://gitlab.com/morley-framework/morley/-/issues/275) in our -- repo as well.-newtype EpName = EpNameUnsafe { unEpName :: Text }+newtype EpName = UnsafeEpName { unEpName :: Text } deriving stock (Show, Eq, Ord, Generic) instance NFData EpName@@ -73,18 +75,18 @@ -- for backwards compatibility and for the cases when you are sure that -- 'EpName' does not come from the @SELF@ instruction. pattern DefEpName :: EpName-pattern DefEpName = EpNameUnsafe ""+pattern DefEpName = UnsafeEpName "" -- | Check whether given 'EpName' refers to the default entrypoint. -- Unlike 'DefEpName' pattern, this function correctly handles all cases, -- including the @SELF@ instruction. isDefEpName :: EpName -> Bool-isDefEpName epName = epName == DefEpName || epName == EpNameUnsafe "default"+isDefEpName epName = epName == DefEpName || epName == UnsafeEpName "default" instance Buildable EpName where build = \case DefEpName -> "<default>"- EpNameUnsafe name -> build name+ UnsafeEpName name -> build name -- | Make up 'EpName' from annotation in parameter type declaration. --@@ -92,14 +94,14 @@ epNameFromParamAnn :: FieldAnn -> Maybe EpName epNameFromParamAnn an@(Annotation a) | an == noAnn = Nothing- | a == "default" = Just (EpNameUnsafe "")- | otherwise = Just $ EpNameUnsafe a+ | a == "default" = Just (UnsafeEpName "")+ | otherwise = Just $ UnsafeEpName a -- | Turn entrypoint name into annotation for contract parameter declaration. epNameToParamAnn :: EpName -> FieldAnn-epNameToParamAnn (EpNameUnsafe name)+epNameToParamAnn (UnsafeEpName name) | name == "" = [annQ|default|]- | otherwise = mkAnnotationUnsafe name+ | otherwise = unsafeMkAnnotation name data EpNameFromRefAnnError = InEpNameBadAnnotation FieldAnn@@ -108,9 +110,12 @@ instance NFData EpNameFromRefAnnError instance Buildable EpNameFromRefAnnError where- build = \case+ build = buildRenderDoc++instance RenderDoc EpNameFromRefAnnError where+ renderDoc _ = \case InEpNameBadAnnotation (Annotation an) ->- "Invalid entrypoint reference `" +| an |+ "`"+ "Invalid entrypoint reference" <+> (enclose "`" "`" $ renderAnyBuildable an) -- | Make up 'EpName' from annotation which is reference to an entrypoint. -- Note that it's more common for Michelson to prohibit explicit @default@@@ -124,16 +129,16 @@ epNameFromRefAnn :: FieldAnn -> Either EpNameFromRefAnnError EpName epNameFromRefAnn an@(Annotation a) | a == "default" = Left $ InEpNameBadAnnotation an- | otherwise = Right $ EpNameUnsafe a+ | otherwise = Right $ UnsafeEpName a -- | Make up an 'EpName' from an annotation which is part of the -- @SELF@ instruction. epNameFromSelfAnn :: FieldAnn -> EpName-epNameFromSelfAnn (Annotation a) = EpNameUnsafe a+epNameFromSelfAnn (Annotation a) = UnsafeEpName a -- | Turn entrypoint name into annotation used as reference to entrypoint. epNameToRefAnn :: EpName -> FieldAnn-epNameToRefAnn (EpNameUnsafe name) = mkAnnotationUnsafe name+epNameToRefAnn (UnsafeEpName name) = unsafeMkAnnotation name -- | Make a valid entrypoint name from an arbitrary text. This -- function prohibits explicit @default@ entrypoint name which is
src/Michelson/Untyped/Instr.hs view
@@ -9,9 +9,6 @@ , ExpandedOp (..) , ExpandedInstr , flattenExpandedOp-- -- * Contract's address- , OperationHash (..) ) where import Prelude hiding (EQ, GT, LT)@@ -33,7 +30,6 @@ import Michelson.Untyped.Ext (ExtInstrAbstract) import Michelson.Untyped.Type (Ty) import Michelson.Untyped.Value (Value'(..))-import Tezos.Address (OperationHash(..)) import Util.Aeson -------------------------------------@@ -121,6 +117,7 @@ | UNIT TypeAnn VarAnn | IF_NONE [op] [op] | PAIR TypeAnn VarAnn FieldAnn FieldAnn+ | UNPAIR VarAnn VarAnn FieldAnn FieldAnn | PAIRN VarAnn Word | UNPAIRN Word | CAR VarAnn FieldAnn@@ -205,6 +202,10 @@ | LEVEL VarAnn | SELF_ADDRESS VarAnn | NEVER+ | TICKET VarAnn+ | READ_TICKET VarAnn+ | SPLIT_TICKET VarAnn+ | JOIN_TICKETS VarAnn deriving stock (Eq, Functor, Data, Generic) instance RenderDoc (InstrAbstract op) => Show (InstrAbstract op) where@@ -242,6 +243,7 @@ UNIT ta va -> "UNIT" <+> renderAnnots [ta] [] [va] IF_NONE x y -> "IF_NONE" <+> nest 9 (renderOps x) <$$> spaces 8 <> nest 9 (renderOps y) PAIR ta va fa1 fa2 -> "PAIR" <+> renderAnnots [ta] [fa1, fa2] [va]+ UNPAIR va1 va2 fa1 fa2 -> "UNPAIR" <+> renderAnnots [] [fa1, fa2] [va1, va2] PAIRN va n -> "PAIR" <+> renderAnnots [] [] [va] <+> text (show n) UNPAIRN n -> "UNPAIR" <+> text (show n) CAR va fa -> "CAR" <+> renderAnnots [] [fa] [va]@@ -328,6 +330,10 @@ LEVEL va -> "LEVEL" <+> renderAnnot va SELF_ADDRESS va -> "SELF_ADDRESS" <+> renderAnnot va NEVER -> "NEVER"+ TICKET va -> "TICKET" <+> renderAnnot va+ READ_TICKET va -> "READ_TICKET" <+> renderAnnot va+ SPLIT_TICKET va -> "SPLIT_TICKET" <+> renderAnnot va+ JOIN_TICKETS va -> "JOIN_TICKETS" <+> renderAnnot va where renderTy = renderDoc @Ty needsParens renderComp = renderDoc @Ty needsParens
src/Michelson/Untyped/OpSize.hs view
@@ -79,6 +79,7 @@ UNIT ta va -> annsOpSize ta va IF_NONE l r -> ifOpSize l r PAIR ta va fal far -> annsOpSize ta va fal far+ UNPAIR va1 va2 fal far -> annsOpSize va1 va2 fal far PAIRN va n -> annsOpSize va <> stackDepthOpSize n UNPAIRN n -> stackDepthOpSize n CAR va fa -> annsOpSize va fa@@ -164,6 +165,10 @@ LEVEL va -> annsOpSize va SELF_ADDRESS va -> annsOpSize va NEVER -> mempty+ TICKET va -> annsOpSize va+ READ_TICKET va -> annsOpSize va+ SPLIT_TICKET va -> annsOpSize va+ JOIN_TICKETS va -> annsOpSize va where subcodeOpSize is = expandedInstrOpSize (SeqEx is) ifOpSize l r = expandedInstrOpSize (SeqEx l) <> expandedInstrOpSize (SeqEx r)@@ -225,6 +230,7 @@ TList a -> typeOpSize a TSet a -> innerOpSize a TOperation -> mempty+ TTicket a -> typeOpSize a TContract a -> typeOpSize a -- Nested variable annotations don't use any extra operation size. TPair al ar _ _ l r -> typeOpSize' [al] l <> typeOpSize' [ar] r
src/Michelson/Untyped/Type.hs view
@@ -46,7 +46,8 @@ (Prettier(..), RenderContext, RenderDoc(..), addParens, buildRenderDoc, doesntNeedParens, needsParens, wrapInParens) import Michelson.Untyped.Annotation- (AnnotationSet, FieldAnn, RootAnn, TypeAnn, VarAnn, emptyAnnSet, fullAnnSet, noAnn, singleAnnSet)+ (AnnotationSet, FieldAnn, RootAnn, TypeAnn, VarAnn, emptyAnnSet, fullAnnSet, noAnn,+ pattern Annotation, singleAnnSet) import Util.Aeson -- Annotated type.@@ -101,10 +102,17 @@ renderType t forceSingleLine pn annSet = let annDoc = renderDoc doesntNeedParens annSet recRenderer t' annSet' = renderType t' forceSingleLine needsParens annSet'- renderBranches d1 d2 =+ renderBranches :: [Doc] -> Doc+ renderBranches ds = if forceSingleLine- then (d1 <+> d2)- else align $ softbreak <> (d1 <$> d2)+ then foldl1 (<+>) ds+ else align $ softbreak <> foldl1 (<$>) ds++ collectBranches :: T -> TypeAnn -> FieldAnn -> [Doc]+ collectBranches (TPair fa1 fa2 va1 _ (Ty t1 ta1) (Ty t2 ta2)) _ (Annotation "")+ = (recRenderer t1 $ (fullAnnSet [ta1] [fa1] [va1])) : collectBranches t2 ta2 fa2+ collectBranches t' ta fa = [recRenderer t' $ fullAnnSet [ta] [fa] []]+ in case t of TInt -> wrapInParens pn $ "int" :| [annDoc]@@ -142,40 +150,58 @@ addParens pn $ "contract" <+> annDoc <+> recRenderer t1 (singleAnnSet ta1) + TTicket (Ty t1 ta1) ->+ addParens pn $+ "ticket" <+> annDoc <+> recRenderer t1 (singleAnnSet ta1)++ -- Optimize in comb pair rendering: `pair x y z` instead of `pair x (pair y z)`+ -- Works only if there is no field annotation on nested pair+ p@(TPair _ (Annotation "") _ _ (Ty _ _) (Ty (TPair {}) _)) ->+ let branches = collectBranches p noAnn noAnn+ in+ addParens pn $+ "pair" <+> annDoc <+>+ renderBranches branches+ TPair fa1 fa2 va1 va2 (Ty t1 ta1) (Ty t2 ta2) -> addParens pn $ "pair" <+> annDoc <+> renderBranches- (recRenderer t1 $ fullAnnSet [ta1] [fa1] [va1])- (recRenderer t2 $ fullAnnSet [ta2] [fa2] [va2])+ [ recRenderer t1 $ fullAnnSet [ta1] [fa1] [va1]+ , recRenderer t2 $ fullAnnSet [ta2] [fa2] [va2]+ ] TOr fa1 fa2 (Ty t1 ta1) (Ty t2 ta2) -> addParens pn $ "or" <+> annDoc <+> renderBranches- (recRenderer t1 $ fullAnnSet [ta1] [fa1] [])- (recRenderer t2 $ fullAnnSet [ta2] [fa2] [])+ [ recRenderer t1 $ fullAnnSet [ta1] [fa1] []+ , recRenderer t2 $ fullAnnSet [ta2] [fa2] []+ ] TLambda (Ty t1 ta1) (Ty t2 ta2) -> addParens pn $ "lambda" <+> annDoc <+> renderBranches- (recRenderer t1 $ singleAnnSet ta1)- (recRenderer t2 $ singleAnnSet ta2)+ [ recRenderer t1 $ singleAnnSet ta1+ , recRenderer t2 $ singleAnnSet ta2+ ] TMap (Ty t1 ta1) (Ty t2 ta2) -> addParens pn $ "map" <+> annDoc <+> renderBranches- (recRenderer t1 $ singleAnnSet ta1)- (recRenderer t2 $ singleAnnSet ta2)+ [ recRenderer t1 $ singleAnnSet ta1+ , recRenderer t2 $ singleAnnSet ta2+ ] TBigMap (Ty t1 ta1) (Ty t2 ta2) -> addParens pn $ "big_map" <+> annDoc <+> renderBranches- (recRenderer t1 $ singleAnnSet ta1)- (recRenderer t2 $ singleAnnSet ta2)+ [ recRenderer t1 $ singleAnnSet ta1+ , recRenderer t2 $ singleAnnSet ta2+ ] instance Buildable Ty where build = buildRenderDoc@@ -194,6 +220,7 @@ | TSet Ty | TOperation | TContract Ty+ | TTicket Ty | TPair FieldAnn FieldAnn VarAnn VarAnn Ty Ty | TOr FieldAnn FieldAnn Ty Ty | TLambda Ty Ty
src/Michelson/Untyped/Value.hs view
@@ -10,11 +10,13 @@ -- Internal types to avoid orphan instances , InternalByteString(..) , unInternalByteString+ , linearizeRightCombValuePair ) where import Data.Aeson (FromJSON(..), ToJSON(..), withText) import Data.Aeson.TH (deriveJSON) import Data.Data (Data(..))+import Data.List.NonEmpty ((<|)) import Fmt (Buildable(build)) import Text.Hex (decodeHex, encodeHex) import Text.PrettyPrint.Leijen.Text@@ -39,7 +41,7 @@ | ValueNone | ValueNil | ValueSeq (NonEmpty $ Value' op)- -- ^ A sequence of elements: can be a list or a set.+ -- ^ A sequence of elements: can be a list, a set or a pair. -- We can't distinguish lists and sets during parsing. | ValueMap (NonEmpty $ Elt op) | ValueLambda (NonEmpty op)@@ -72,6 +74,9 @@ ValueUnit -> "Unit" ValueTrue -> "True" ValueFalse -> "False"+ p@(ValuePair _ (ValuePair _ _)) ->+ let encodedValues = linearizeRightCombValuePair p+ in renderValuesList (renderDoc doesntNeedParens) encodedValues ValuePair l r -> addParens pn $ "Pair" <+> renderDoc needsParens l <+> renderDoc needsParens r ValueLeft l -> addParens pn $@@ -84,6 +89,11 @@ ValueSeq xs -> renderValuesList (renderDoc doesntNeedParens) xs ValueMap xs -> renderValuesList renderElt xs ValueLambda xs -> renderOps False xs++-- | Converts `Pair a (Pair b c)` to `[a, b, c].`+linearizeRightCombValuePair :: (Value' op) -> NonEmpty (Value' op)+linearizeRightCombValuePair (ValuePair l r) = l <| linearizeRightCombValuePair r+linearizeRightCombValuePair v = v :| [] renderElt :: RenderDoc op => Elt op -> Doc renderElt (Elt k v) =
src/Morley/Micheline/Binary.hs view
@@ -10,6 +10,7 @@ ( decodeExpression , eitherDecodeExpression , encodeExpression+ , encodeExpression' ) where import qualified Data.Binary.Builder as Bi@@ -17,7 +18,6 @@ import Data.Bits (Bits, bit, setBit, shift, testBit, zeroBits, (.&.), (.|.)) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS-import Data.Sequence (Seq((:<|))) import qualified Data.Sequence as Seq import qualified Data.Text.Encoding as TE @@ -31,20 +31,24 @@ ------------------------------------------------- -- | Encode 'Expression' to 'ByteString'.-encodeExpression :: Expression -> BS.ByteString-encodeExpression = LBS.toStrict . Bi.toLazyByteString . buildExpr+encodeExpression :: Expression -> LByteString+encodeExpression = Bi.toLazyByteString . buildExpr +-- | Same as 'encodeExpression', for strict bytestring.+encodeExpression' :: Expression -> BS.ByteString+encodeExpression' = LBS.toStrict . encodeExpression+ buildExpr :: Expression -> Bi.Builder buildExpr = \case- ExpressionSeq xs -> buildWord8 2 <> buildDynamic buildSeq (DynamicSize xs)+ ExpressionSeq xs -> buildWord8 2 <> buildDynamic buildList (DynamicSize xs) ExpressionPrim (MichelinePrimAp prim args annots) -> case (args, annots) of- (Seq.Empty, Seq.Empty) -> buildWord8 3 <> buildPrim prim- (Seq.Empty, _) -> buildWord8 4 <> buildPrim prim <> buildAnnotationSeq annots- (arg1 :<| Seq.Empty, Seq.Empty) -> buildWord8 5 <> buildPrim prim <> buildExpr arg1- (arg1 :<| Seq.Empty, _) -> buildWord8 6 <> buildPrim prim <> buildExpr arg1 <> buildAnnotationSeq annots- (arg1 :<| (arg2 :<| Seq.Empty), Seq.Empty) -> buildWord8 7 <> buildPrim prim <> buildExpr arg1 <> buildExpr arg2- (arg1 :<| (arg2 :<| Seq.Empty), _) -> buildWord8 8 <> buildPrim prim <> buildExpr arg1 <> buildExpr arg2 <> buildAnnotationSeq annots- _ -> buildWord8 9 <> buildPrim prim <> buildDynamic buildSeq (DynamicSize args) <> buildAnnotationSeq annots+ ([], []) -> buildWord8 3 <> buildPrim prim+ ([], _) -> buildWord8 4 <> buildPrim prim <> buildAnnotationList annots+ ([arg1], []) -> buildWord8 5 <> buildPrim prim <> buildExpr arg1+ ([arg1], _) -> buildWord8 6 <> buildPrim prim <> buildExpr arg1 <> buildAnnotationList annots+ ([arg1, arg2], []) -> buildWord8 7 <> buildPrim prim <> buildExpr arg1 <> buildExpr arg2+ ([arg1, arg2], _) -> buildWord8 8 <> buildPrim prim <> buildExpr arg1 <> buildExpr arg2 <> buildAnnotationList annots+ _ -> buildWord8 9 <> buildPrim prim <> buildDynamic buildList (DynamicSize args) <> buildAnnotationList annots ExpressionString x -> buildWord8 1 <> buildDynamic buildText (DynamicSize x) ExpressionInt x -> buildWord8 0 <> buildInteger x ExpressionBytes x -> buildWord8 10 <> buildDynamic buildByteString (DynamicSize x)@@ -78,16 +82,16 @@ buildText n = buildByteString $ TE.encodeUtf8 n -buildSeq :: Seq Expression -> Bi.Builder-buildSeq xs = foldMap buildExpr xs+buildList :: [Expression] -> Bi.Builder+buildList = foldMap buildExpr buildPrim :: MichelinePrimitive -> Bi.Builder buildPrim (MichelinePrimitive p) = case Seq.elemIndexL p michelsonPrimitive of Nothing -> error $ "unknown Michelson/Micheline primitive: " <> p Just ix -> buildWord8 (fromIntegral ix) -buildAnnotationSeq :: Seq Annotation -> Bi.Builder-buildAnnotationSeq seqAnn = buildDynamic buildText (DynamicSize $ unwords . toList . fmap annotToText $ seqAnn)+buildAnnotationList :: [Annotation] -> Bi.Builder+buildAnnotationList listAnn = buildDynamic buildText (DynamicSize $ unwords . fmap annotToText $ listAnn) ------------------------------------------------- -- Decode@@ -105,14 +109,14 @@ getExpr = Bi.getWord8 >>= \case 0 -> ExpressionInt <$> getInteger 1 -> ExpressionString . unDynamicSize <$> (getDynamic getText)- 2 -> ExpressionSeq . unDynamicSize <$> (getDynamic getSeq)- 3 -> ExpressionPrim . (\pn -> MichelinePrimAp pn Seq.Empty Seq.Empty) <$> getPrim- 4 -> ExpressionPrim <$> (flip MichelinePrimAp Seq.Empty <$> getPrim <*> getAnnotationSeq)- 5 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> (Seq.singleton <$> getExpr) <*> pure Seq.empty)- 6 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> (Seq.singleton <$> getExpr) <*> getAnnotationSeq)- 7 -> ExpressionPrim <$> ((\n a -> MichelinePrimAp n a Seq.empty) <$> getPrim <*> Seq.replicateA 2 getExpr)- 8 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> Seq.replicateA 2 getExpr <*> getAnnotationSeq)- 9 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> (unDynamicSize <$> (getDynamic getSeq)) <*> getAnnotationSeq)+ 2 -> ExpressionSeq . unDynamicSize <$> (getDynamic getList)+ 3 -> ExpressionPrim . (\pn -> MichelinePrimAp pn [] []) <$> getPrim+ 4 -> ExpressionPrim <$> (flip MichelinePrimAp [] <$> getPrim <*> getAnnotationList)+ 5 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> (one <$> getExpr) <*> pure [])+ 6 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> (one <$> getExpr) <*> getAnnotationList)+ 7 -> ExpressionPrim <$> ((\n a -> MichelinePrimAp n a []) <$> getPrim <*> replicateM 2 getExpr)+ 8 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> replicateM 2 getExpr <*> getAnnotationList)+ 9 -> ExpressionPrim <$> (MichelinePrimAp <$> getPrim <*> (unDynamicSize <$> (getDynamic getList)) <*> getAnnotationList) 10 -> ExpressionBytes . unDynamicSize <$> (getDynamic getByteString) _ -> fail "invalid Micheline expression tag" @@ -145,9 +149,8 @@ getByteString = LBS.toStrict <$> Bi.getRemainingLazyByteString -getSeq :: Bi.Get (Seq Expression)-getSeq =- Seq.fromList <$> many getExpr+getList :: Bi.Get [Expression]+getList = many getExpr getPrim :: Bi.Get MichelinePrimitive getPrim =@@ -155,5 +158,5 @@ Nothing -> fail "unknown Michelson/Micheline opcode" Just str -> pure $ MichelinePrimitive str -getAnnotationSeq :: Bi.Get (Seq Annotation)-getAnnotationSeq = mapM annotFromText . Seq.fromList . words . unDynamicSize =<< (getDynamic getText)+getAnnotationList :: Bi.Get [Annotation]+getAnnotationList = mapM annotFromText . words . unDynamicSize =<< (getDynamic getText)
src/Morley/Micheline/Class.hs view
@@ -10,88 +10,301 @@ , FromExpression (..) ) where -import qualified Data.ByteString.Lazy as LBS-import Data.Sequence (fromList, (|>))-import Data.Singletons (Sing, SingI, SomeSing (..), toSing, withSingI)-import Fmt (Buildable(..), pretty)+import Control.Lens ((<>~))+import Data.Bits (toIntegralSized)+import Data.Default+import Data.Singletons (SingI(..), demote)+import Fmt (Buildable(..), indentF, pretty, unlinesF) -import Michelson.Interpret.Pack (encodeValue', packCode', packNotedT', packT')-import Michelson.Interpret.Unpack- (UnpackError, decodeContract, decodeType, unpackInstr', unpackValue')+import Michelson.Text (mkMText, unMText)+import Michelson.TypeCheck (TypeCheckMode(..), TypeCheckOptions(..), runTypeCheck, typeCheckingWith)+import Michelson.TypeCheck.Instr (typeCheckValue) import Michelson.Typed- (pattern AsUType, Contract(..), HasNoOp, Instr(..), KnownT, Notes(..), T(..), Value, Value'(..),- fromUType, pnNotes, pnRootAnn, rfAnyInstr)-import Michelson.Typed.Instr (mapEntriesOrdered)-import Michelson.Typed.Scope (UnpackedValScope)+ (Contract(..), HasNoOp, Instr, Notes(..), T(..), Value, Value'(..), fromUType, mkUType,+ rfAnyInstr, toUType)+import Michelson.Typed.Convert (convertContract, instrToOpsOptimized, untypeValueOptimized) import qualified Michelson.Untyped as Untyped-import Michelson.Untyped.Annotation (RootAnn, noAnn)-import Michelson.Untyped.Instr (ExpandedOp)-import Morley.Micheline.Binary (decodeExpression, encodeExpression)+import Michelson.Untyped.Annotation+ (AnnotationSet(..), FieldAnn, FieldTag, RootAnn, TypeAnn, TypeTag, VarAnn, VarTag, annsCount,+ emptyAnnSet, firstAnn, noAnn, secondAnn)+import Michelson.Untyped.Contract (ContractBlock(..), orderContractBlock)+import Michelson.Untyped.Instr (ExpandedInstr, ExpandedOp(..), InstrAbstract(..))+import Michelson.Untyped.Type (Ty(..)) import Morley.Micheline.Expression- (Annotation(..), Expression(..), MichelinePrimAp(..), MichelinePrimitive(..))-import Util.Binary (launchGet)+ (Annotation(..), Expression(..), MichelinePrimAp(..), _ExpressionPrim, isAnnotationField,+ isAnnotationType, isAnnotationVariable, mkAnns, mpaAnnotsL, toAnnSet) -- | Type class that provides an ability to convert -- something to Micheline Expression. class ToExpression a where toExpression :: a -> Expression +instance forall t . (SingI t, HasNoOp t) => ToExpression (Value t) where+ toExpression = toExpression . untypeValueOptimized++instance ToExpression Untyped.Value where+ toExpression = \case+ Untyped.ValueInt v -> ExpressionInt v+ Untyped.ValueString s -> ExpressionString $ unMText s+ Untyped.ValueBytes (Untyped.InternalByteString bs) -> ExpressionBytes bs+ Untyped.ValueUnit -> PrimExpr "Unit" [] []+ Untyped.ValueTrue -> PrimExpr "True" [] []+ Untyped.ValueFalse -> PrimExpr "False" [] []+ Untyped.ValuePair l r ->+ PrimExpr "Pair" [toExpression l, toExpression r] []+ Untyped.ValueLeft v -> PrimExpr "Left" [toExpression v] []+ Untyped.ValueRight v -> PrimExpr "Right" [toExpression v] []+ Untyped.ValueSome v -> PrimExpr "Some" [toExpression v] []+ Untyped.ValueNone -> PrimExpr "None" [] []+ Untyped.ValueNil -> ExpressionSeq []+ Untyped.ValueSeq vs -> toExpression vs+ Untyped.ValueMap elts -> toExpression $ eltToExpr <$> elts+ Untyped.ValueLambda ops -> toExpression ops+ where+ eltToExpr :: Untyped.Elt ExpandedOp -> Expression+ eltToExpr (Untyped.Elt l r) = PrimExpr "Elt"+ [toExpression l, toExpression r] []++ instance ToExpression (Instr inp out) where- toExpression = decodeExpression . packCode'+ toExpression = toExpression . instrToOpsOptimized instance ToExpression T where- toExpression t' | SomeSing (ts :: Sing t) <- toSing t' =- decodeExpression $ withSingI ts $ (packT' @t)+ toExpression = toExpression . toUType instance SingI t => ToExpression (Notes t) where- toExpression = decodeExpression . packNotedT'+ toExpression = toExpression . mkUType -instance ToExpression Untyped.Ty where- toExpression (AsUType notes) = toExpression notes+instance ToExpression Untyped.T where+ toExpression = \case+ Untyped.TKey -> PrimExpr "key" [] []+ Untyped.TUnit -> PrimExpr "unit" [] []+ Untyped.TSignature -> PrimExpr "signature" [] []+ Untyped.TChainId -> PrimExpr "chain_id" [] []+ Untyped.TOption arg -> PrimExpr "option" [toExpression arg] []+ Untyped.TList arg -> PrimExpr "list" [toExpression arg] []+ Untyped.TSet arg -> PrimExpr "set" [toExpression arg] []+ Untyped.TOperation -> PrimExpr "operation" [] []+ Untyped.TContract arg -> PrimExpr "contract" [toExpression arg] []+ Untyped.TTicket arg -> PrimExpr "ticket" [toExpression arg] []+ t@Untyped.TPair{} -> PrimExpr "pair"+ (rightCombedPairToList (Ty t noAnn) (noAnn, noAnn)) []+ Untyped.TOr fa1 fa2 l r ->+ let exprL = addTrimmedAnns (toExpression l) [] [fa1] []+ exprR = addTrimmedAnns (toExpression r) [] [fa2] []+ in PrimExpr "or" [exprL, exprR] []+ Untyped.TLambda inp out ->+ PrimExpr "lambda" [toExpression inp, toExpression out] []+ Untyped.TMap k v ->+ PrimExpr "map" [toExpression k, toExpression v] []+ Untyped.TBigMap k v ->+ PrimExpr "big_map" [toExpression k, toExpression v] []+ Untyped.TInt -> PrimExpr "int" [] []+ Untyped.TNat -> PrimExpr "nat" [] []+ Untyped.TString -> PrimExpr "string" [] []+ Untyped.TBytes -> PrimExpr "bytes" [] []+ Untyped.TMutez -> PrimExpr "mutez" [] []+ Untyped.TBool -> PrimExpr "bool" [] []+ Untyped.TKeyHash -> PrimExpr "key_hash" [] []+ Untyped.TBls12381Fr -> PrimExpr "bls12_381_fr" [] []+ Untyped.TBls12381G1 -> PrimExpr "bls12_381_g1" [] []+ Untyped.TBls12381G2 -> PrimExpr "bls12_381_g2" [] []+ Untyped.TTimestamp -> PrimExpr "timestamp" [] []+ Untyped.TAddress -> PrimExpr "address" [] []+ Untyped.TNever -> PrimExpr "never" [] [] -instance (SingI t, HasNoOp t) => ToExpression (Value t) where- toExpression = decodeExpression . encodeValue'+ where+ addAnns :: Expression -> [Annotation] -> Expression+ addAnns e anns =+ e & _ExpressionPrim . mpaAnnotsL <>~ anns -instance ToExpression (Contract cp st) where- toExpression contract@Contract{} = ExpressionSeq $ fromList $ mapEntriesOrdered contract- (\param -> ExpressionPrim $- MichelinePrimAp (MichelinePrimitive "parameter")- (fromList [ addRootAnnToExpression (pnRootAnn param) $- toExpression $ pnNotes param- ])- (fromList [])- )- (\store -> ExpressionPrim $- MichelinePrimAp (MichelinePrimitive "storage")- (fromList [toExpression $ store])- (fromList [])- )- (\code -> ExpressionPrim $- MichelinePrimAp (MichelinePrimitive "code")- (fromList [toExpression code])- (fromList [])- )+ rightCombedPairToList :: Ty -> (FieldAnn, VarAnn) -> [Expression]+ rightCombedPairToList ty (fa, va) = case (ty, fa) of+ (Ty (Untyped.TPair fa1 fa2 va1 va2 l r) (Untyped.Annotation ""), Untyped.Annotation "") ->+ let annsL = mkAnns [] [fa1] [va1]+ exprL = toExpression l `addAnns` annsL+ in exprL : (rightCombedPairToList r (fa2, va2))+ _ ->+ let anns = mkAnns [] [fa] [va]+ in one $ toExpression ty `addAnns` anns++instance ToExpression Ty where+ toExpression (Ty t ta) = addTrimmedAnns (toExpression t) [ta] [] []++instance (ToExpression a) => ToExpression [a] where+ toExpression xs = ExpressionSeq $ toExpression <$> xs++instance (ToExpression a) => ToExpression (NonEmpty a) where+ toExpression = toExpression . toList++instance ToExpression Expression where+ toExpression = id++instance ToExpression ExpandedOp where+ toExpression = \case+ PrimEx instr -> toExpression instr+ SeqEx s -> ExpressionSeq $ toExpression <$> s+ WithSrcEx _ op -> toExpression op++instance ToExpression ExpandedInstr where+ toExpression = \case+ PUSH va ty v -> PrimExpr "PUSH" [toExpression ty, toExpression v] $+ mkAnns [] [] [va]+ DROP -> PrimExpr "DROP" [] []+ DROPN n -> PrimExpr "DROP" [wordToExpr n] []+ DUP va -> PrimExpr "DUP" [] $ mkAnns [] [] [va]+ DUPN va n -> PrimExpr "DUP" [wordToExpr n] $ mkAnns [] [] [va]+ SWAP -> PrimExpr "SWAP" [] []+ DIG n -> PrimExpr "DIG" [wordToExpr n] []+ DUG n -> PrimExpr "DUG" [wordToExpr n] []+ SOME ta va ->+ PrimExpr "SOME" [] $ mkAnns [ta] [] [va]+ NONE ta va ty -> PrimExpr "NONE" [toExpression ty] $ mkAnns [ta] [] [va]+ UNIT ta va -> PrimExpr "UNIT" [] $ mkAnns [ta] [] [va]+ IF_NONE ops1 ops2 ->+ PrimExpr "IF_NONE" [toExpression ops1, toExpression ops2] []+ PAIR ta va fa1 fa2 -> PrimExpr "PAIR" [] $ mkAnns [ta] [fa1, fa2] [va]+ UNPAIR va1 va2 fa1 fa2 -> PrimExpr "UNPAIR" [] $+ mkAnns [] [fa1, fa2] [va1, va2]+ PAIRN va n -> PrimExpr "PAIR" [wordToExpr n] $ mkAnns [] [] [va]+ UNPAIRN n -> PrimExpr "UNPAIR" [wordToExpr n] []+ CAR va fa -> PrimExpr "CAR" [] $ mkAnns [] [fa] [va]+ CDR va fa -> PrimExpr "CDR" [] $ mkAnns [] [fa] [va]+ LEFT ta va fa1 fa2 ty -> PrimExpr "LEFT" [toExpression ty] $+ mkAnns [ta] [fa1, fa2] [va]+ RIGHT ta va fa1 fa2 ty -> PrimExpr "RIGHT" [toExpression ty] $+ mkAnns [ta] [fa1, fa2] [va]+ IF_LEFT ops1 ops2 ->+ PrimExpr "IF_LEFT" [toExpression ops1, toExpression ops2] []+ NIL ta va ty -> PrimExpr "NIL" [toExpression ty] $+ mkAnns [ta] [] [va]+ CONS va -> PrimExpr "CONS" [] $ mkAnns [] [] [va]+ IF_CONS ops1 ops2 ->+ PrimExpr "IF_CONS" [toExpression ops1, toExpression ops2] []+ SIZE va -> PrimExpr "SIZE" [] $ mkAnns [] [] [va]+ EMPTY_SET ta va ty -> PrimExpr "EMPTY_SET" [toExpression ty] $+ mkAnns [ta] [] [va]+ EMPTY_MAP ta va kty vty ->+ PrimExpr "EMPTY_MAP" [toExpression kty, toExpression vty] $+ mkAnns [ta] [] [va]+ EMPTY_BIG_MAP ta va kty vty ->+ PrimExpr "EMPTY_BIG_MAP" [toExpression kty, toExpression vty] $+ mkAnns [ta] [] [va]+ MAP va ops -> PrimExpr "MAP" [toExpression ops] $ mkAnns [] [] [va]+ ITER ops -> PrimExpr "ITER" [toExpression ops] []+ MEM va -> PrimExpr "MEM" [] $ mkAnns [] [] [va]+ GET va -> PrimExpr "GET" [] $ mkAnns [] [] [va]+ GETN va n -> PrimExpr "GET" [wordToExpr n] $ mkAnns [] [] [va]+ UPDATE va -> PrimExpr "UPDATE" [] $ mkAnns [] [] [va]+ UPDATEN va n -> PrimExpr "UPDATE" [wordToExpr n] $ mkAnns [] [] [va]+ GET_AND_UPDATE va -> PrimExpr "GET_AND_UPDATE" [] $ mkAnns [] [] [va]+ IF ops1 ops2 ->+ PrimExpr "IF" [toExpression ops1, toExpression ops2] []+ LOOP ops -> PrimExpr "LOOP" [toExpression ops] []+ LOOP_LEFT ops -> PrimExpr "LOOP_LEFT" [toExpression ops] []+ LAMBDA va tyin tyout ops ->+ PrimExpr "LAMBDA" [ toExpression tyin+ , toExpression tyout+ , toExpression ops+ ] $ mkAnns [] [] [va]+ EXEC va -> PrimExpr "EXEC" [] $ mkAnns [] [] [va]+ APPLY va -> PrimExpr "APPLY" [] $ mkAnns [] [] [va]+ DIP ops -> PrimExpr "DIP" [toExpression ops] []+ DIPN n ops -> PrimExpr "DIP" [wordToExpr n, toExpression ops] []+ FAILWITH -> PrimExpr "FAILWITH" [] []+ CAST va ty -> PrimExpr "CAST" [toExpression ty] $ mkAnns [] [] [va]+ RENAME va -> PrimExpr "RENAME" [] $ mkAnns [] [] [va]+ PACK va -> PrimExpr "PACK" [] $ mkAnns [] [] [va]+ UNPACK ta va ty -> PrimExpr "UNPACK" [toExpression ty] $+ mkAnns [ta] [] [va]+ CONCAT va -> PrimExpr "CONCAT" [] $ mkAnns [] [] [va]+ SLICE va -> PrimExpr "SLICE" [] $ mkAnns [] [] [va]+ ISNAT va -> PrimExpr "ISNAT" [] $ mkAnns [] [] [va]+ ADD va -> PrimExpr "ADD" [] $ mkAnns [] [] [va]+ SUB va -> PrimExpr "SUB" [] $ mkAnns [] [] [va]+ MUL va -> PrimExpr "MUL" [] $ mkAnns [] [] [va]+ EDIV va -> PrimExpr "EDIV" [] $ mkAnns [] [] [va]+ ABS va -> PrimExpr "ABS" [] $ mkAnns [] [] [va]+ NEG va -> PrimExpr "NEG" [] $ mkAnns [] [] [va]+ LSL va -> PrimExpr "LSL" [] $ mkAnns [] [] [va]+ LSR va -> PrimExpr "LSR" [] $ mkAnns [] [] [va]+ OR va -> PrimExpr "OR" [] $ mkAnns [] [] [va]+ AND va -> PrimExpr "AND" [] $ mkAnns [] [] [va]+ XOR va -> PrimExpr "XOR" [] $ mkAnns [] [] [va]+ NOT va -> PrimExpr "NOT" [] $ mkAnns [] [] [va]+ COMPARE va -> PrimExpr "COMPARE" [] $ mkAnns [] [] [va]+ Untyped.EQ va -> PrimExpr "EQ" [] $ mkAnns [] [] [va]+ NEQ va -> PrimExpr "NEQ" [] $ mkAnns [] [] [va]+ Untyped.LT va -> PrimExpr "LT" [] $ mkAnns [] [] [va]+ Untyped.GT va -> PrimExpr "GT" [] $ mkAnns [] [] [va]+ LE va -> PrimExpr "LE" [] $ mkAnns [] [] [va]+ GE va -> PrimExpr "GE" [] $ mkAnns [] [] [va]+ INT va -> PrimExpr "INT" [] $ mkAnns [] [] [va]+ SELF va fa -> PrimExpr "SELF" [] $ mkAnns [] [fa] [va]+ CONTRACT va fa ty -> PrimExpr "CONTRACT" [toExpression ty] $+ mkAnns [] [fa] [va]+ TRANSFER_TOKENS va -> PrimExpr "TRANSFER_TOKENS" [] $ mkAnns [] [] [va]+ SET_DELEGATE va -> PrimExpr "SET_DELEGATE" [] $ mkAnns [] [] [va]+ CREATE_CONTRACT va1 va2 c ->+ PrimExpr "CREATE_CONTRACT" [toExpression c] $+ mkAnns [] [] [va1, va2]+ IMPLICIT_ACCOUNT va -> PrimExpr "IMPLICIT_ACCOUNT" [] $+ mkAnns [] [] [va]+ NOW va -> PrimExpr "NOW" [] $ mkAnns [] [] [va]+ AMOUNT va -> PrimExpr "AMOUNT" [] $ mkAnns [] [] [va]+ BALANCE va -> PrimExpr "BALANCE" [] $ mkAnns [] [] [va]+ VOTING_POWER va -> PrimExpr "VOTING_POWER" [] $ mkAnns [] [] [va]+ TOTAL_VOTING_POWER va -> PrimExpr "TOTAL_VOTING_POWER" [] $+ mkAnns [] [] [va]+ CHECK_SIGNATURE va -> PrimExpr "CHECK_SIGNATURE" [] $ mkAnns [] [] [va]+ SHA256 va -> PrimExpr "SHA256" [] $ mkAnns [] [] [va]+ SHA512 va -> PrimExpr "SHA512" [] $ mkAnns [] [] [va]+ BLAKE2B va -> PrimExpr "BLAKE2B" [] $ mkAnns [] [] [va]+ SHA3 va -> PrimExpr "SHA3" [] $ mkAnns [] [] [va]+ KECCAK va -> PrimExpr "KECCAK" [] $ mkAnns [] [] [va]+ HASH_KEY va -> PrimExpr "HASH_KEY" [] $ mkAnns [] [] [va]+ PAIRING_CHECK va -> PrimExpr "PAIRING_CHECK" [] $ mkAnns [] [] [va]+ SOURCE va -> PrimExpr "SOURCE" [] $ mkAnns [] [] [va]+ SENDER va -> PrimExpr "SENDER" [] $ mkAnns [] [] [va]+ ADDRESS va -> PrimExpr "ADDRESS" [] $ mkAnns [] [] [va]+ CHAIN_ID va -> PrimExpr "CHAIN_ID" [] $ mkAnns [] [] [va]+ LEVEL va -> PrimExpr "LEVEL" [] $ mkAnns [] [] [va]+ SELF_ADDRESS va -> PrimExpr "SELF_ADDRESS" [] $ mkAnns [] [] [va]+ TICKET va -> PrimExpr "TICKET" [] $ mkAnns [] [] [va]+ READ_TICKET va -> PrimExpr "READ_TICKET" [] $ mkAnns [] [] [va]+ SPLIT_TICKET va -> PrimExpr "SPLIT_TICKET" [] $ mkAnns [] [] [va]+ JOIN_TICKETS va -> PrimExpr "JOIN_TICKETS" [] $ mkAnns [] [] [va]+ NEVER -> PrimExpr "NEVER" [] []+ EXT _ -> ExpressionSeq [] where- addRootAnnToExpression :: HasCallStack =>- RootAnn -> Expression -> Expression- addRootAnnToExpression rootAnn expr = case expr of- ExpressionPrim p- | rootAnn /= noAnn -> ExpressionPrim p- { mpaAnnots = mpaAnnots p |> AnnotationField rootAnn- }- | otherwise -> expr- -- Currently this error can't happen because parameter type- -- must be a Micheline primitive. If it ever changes, we- -- would like to notice it ASAP and update this place.- _ -> error $ "parameter is not a primitive: " <> show expr+ wordToExpr :: Word -> Expression+ wordToExpr = toExpression @(Value 'TInt) . VInt . fromIntegral @Word @Integer +instance ToExpression Untyped.Contract where+ toExpression contract+ = ExpressionSeq $ Untyped.mapEntriesOrdered contract+ (\(Untyped.ParameterType ty rootAnn) -> PrimExpr "parameter"+ [insertRootAnn (toExpression ty) rootAnn] [])+ (\storage -> PrimExpr "storage" [toExpression storage] [])+ (\code -> PrimExpr "code" [toExpression code] [])++instance ToExpression (Contract cp st) where+ toExpression = toExpression . convertContract+ -- | Errors that can happen when we convert an 'Expression' to our -- data type.-data FromExpressionError = FromExpressionError UnpackError+data FromExpressionError = FromExpressionError Expression Text deriving stock (Show, Eq) instance Buildable FromExpressionError where- build (FromExpressionError err) = build err+ build (FromExpressionError expr err) =+ unlinesF+ [ "Failed to convert expression:"+ , indentF 2 $ build expr+ , ""+ , "Error:"+ , indentF 2 $ build err+ ] instance Exception FromExpressionError where displayException = pretty@@ -101,33 +314,621 @@ class FromExpression a where fromExpression :: Expression -> Either FromExpressionError a -instance UnpackedValScope t => FromExpression (Value t) where- -- | `05` is the prefix for serialized Michelson value.- fromExpression =- first FromExpressionError . unpackValue' . ("\05" <>) . encodeExpression+instance (SingI t) => FromExpression (Value t) where+ fromExpression expr =+ case fromExpression @Untyped.Value expr of+ Right uv -> case typeCheck uv of+ Left tcErr -> Left $ FromExpressionError expr $+ pretty $ unlinesF+ [ "Failed to typecheck expression as a value of type:"+ , indentF 2 $ build $ demote @t+ , ""+ , "Typechecker error:"+ , indentF 2 $ build tcErr+ ]+ Right tv -> Right tv+ Left e -> Left e+ where+ typeCheck uv = typeCheckingWith (TypeCheckOptions False False) $+ (runTypeCheck $ TypeCheckValue (uv, demote @t)) $+ usingReaderT def $+ typeCheckValue uv -instance FromExpression [ExpandedOp] where- fromExpression = first FromExpressionError . unpackInstr' . encodeExpression+instance FromExpression Untyped.Value where+ fromExpression e = case e of+ ExpressionInt v -> pure $ Untyped.ValueInt v+ ExpressionString s -> first (FromExpressionError e)+ (Untyped.ValueString <$> mkMText s)+ ExpressionBytes bs -> pure $ Untyped.ValueBytes $ Untyped.InternalByteString bs+ PrimExpr "Unit" [] [] -> pure Untyped.ValueUnit+ PrimExpr "True" [] [] -> pure Untyped.ValueTrue+ PrimExpr "False" [] [] -> pure Untyped.ValueFalse+ PrimExpr "Pair" [l, r] [] -> do+ l' <- fromExpression l+ r' <- fromExpression r+ pure $ Untyped.ValuePair l' r'+ PrimExpr "Pair" args [] ->+ case (nonEmpty args) >>= forbidSingletonList of+ Nothing -> Left $ FromExpressionError e+ "Expected a pair with at least 2 arguments"+ Just args' -> fromExpression $ seqToPairExpr args' "Pair"+ PrimExpr "Left" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.ValueLeft arg'+ PrimExpr "Right" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.ValueRight arg'+ PrimExpr "Some" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.ValueSome arg'+ PrimExpr "None" [] [] -> pure Untyped.ValueNone+ ExpressionSeq [] -> pure Untyped.ValueNil+ ExpressionSeq (h : t) ->+ case fromExpression @Untyped.ExpandedOp h of+ Right op -> do+ ops <- traverse (fromExpression @Untyped.ExpandedOp) t+ pure . Untyped.ValueLambda $ op :| ops+ Left _ -> case exprToElt h of+ Right elt -> do+ elts <- traverse exprToElt t+ pure . Untyped.ValueMap $ elt :| elts+ Left _ -> case fromExpression h of+ Left (FromExpressionError err _) -> Left $ FromExpressionError err+ "Value, instruction or 'Elt' expression expected"+ Right h' -> do+ t' <- traverse fromExpression t+ pure . Untyped.ValueSeq $ h' :| t'+ _ -> Left $ FromExpressionError e "Expected a value"+ where+ exprToElt :: Expression -> Either FromExpressionError (Untyped.Elt ExpandedOp)+ exprToElt ex = case ex of+ PrimExpr "Elt" [l, r] [] -> do+ l' <- fromExpression l+ r' <- fromExpression r+ pure $ Untyped.Elt l' r'+ PrimExpr "Elt" _ [] -> Left $ FromExpressionError ex+ "Expected 'Elt' expression with exactly 2 elements"+ PrimExpr "Elt" _ _ -> Left $ FromExpressionError ex+ "Expected 'Elt' expression without annotations"+ _ -> Left $ FromExpressionError ex "Expected 'Elt' expression" +instance (FromExpression a) => FromExpression [a] where+ fromExpression = \case+ ExpressionSeq exprs -> traverse fromExpression exprs+ e -> Left $ FromExpressionError e "'ExpressionSeq' expected"++instance FromExpression ExpandedOp where+ fromExpression = \case+ ExpressionSeq s -> SeqEx <$> traverse fromExpression s+ e -> PrimEx <$> fromExpression e++instance FromExpression ExpandedInstr where+ fromExpression e = let annSet = getAnnSet e in case e of+ PrimExpr "DROP" [n] [] -> do+ n' <- intExprToWord n+ pure $ DROPN n'+ PrimExpr "DROP" [] _ -> pure $ DROP+ PrimExpr "DUP" [n] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ let va = firstAnn @VarTag annSet+ n' <- intExprToWord n+ pure $ DUPN va n'+ PrimExpr "DUP" [] _ ->+ let va = firstAnn @VarTag annSet+ in checkAnnsCount e annSet (0, 0, 1) $> DUP va+ PrimExpr "SWAP" [] [] -> pure $ SWAP+ PrimExpr "DIG" [n] [] -> do+ n' <- intExprToWord n+ pure $ DIG $ n'+ PrimExpr "DUG" [n] [] -> do+ n' <- intExprToWord n+ pure $ DUG n'+ PrimExpr "PUSH" [t, v] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ let va = firstAnn @VarTag annSet+ t' <- fromExpression @Ty t+ v' <- fromExpression @Untyped.Value v+ pure $ PUSH va t' v'+ PrimExpr "SOME" [] _ ->+ let ta = firstAnn @TypeTag annSet+ va = firstAnn @VarTag annSet+ in checkAnnsCount e annSet (1, 0, 1) $> SOME ta va+ PrimExpr "NONE" [t] _ -> do+ checkAnnsCount e annSet (1, 0, 1)+ let ta = firstAnn @TypeTag annSet+ let va = firstAnn @VarTag annSet+ t' <- fromExpression @Ty t+ pure $ NONE ta va t'+ PrimExpr "UNIT" [] _ ->+ let ta = firstAnn @TypeTag annSet+ va = firstAnn @VarTag annSet+ in checkAnnsCount e annSet (1, 0, 1) $> UNIT ta va+ PrimExpr "IF_NONE" [ops1, ops2] [] -> do+ ops1' <- fromExpression @([ExpandedOp]) ops1+ ops2' <- fromExpression @([ExpandedOp]) ops2+ pure $ IF_NONE ops1' ops2'+ PrimExpr "PAIR" [] _ ->+ let ta = firstAnn @TypeTag annSet+ va = firstAnn @VarTag annSet+ fa1 = firstAnn @FieldTag annSet+ fa2 = secondAnn @FieldTag annSet+ in (checkAnnsCount e annSet (1, 2, 1)) $> PAIR ta va fa1 fa2+ PrimExpr "UNPAIR" [] _ ->+ let va1 = firstAnn @VarTag annSet+ va2 = secondAnn @VarTag annSet+ fa1 = firstAnn @FieldTag annSet+ fa2 = secondAnn @FieldTag annSet+ in checkAnnsCount e annSet (0, 2, 2) $> UNPAIR va1 va2 fa1 fa2+ PrimExpr "PAIR" [n] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ n' <- intExprToWord n+ let va = firstAnn @VarTag annSet+ pure $ PAIRN va n'+ PrimExpr "UNPAIR" [n] [] -> do+ n' <- intExprToWord n+ pure $ UNPAIRN n'+ PrimExpr "CAR" [] _ ->+ let va = firstAnn @VarTag annSet+ fa = firstAnn @FieldTag annSet+ in checkAnnsCount e annSet (0, 1, 1) $> CAR va fa+ PrimExpr "CDR" [] _ ->+ let va = firstAnn @VarTag annSet+ fa = firstAnn @FieldTag annSet+ in checkAnnsCount e annSet (0, 1, 1) $> CDR va fa+ PrimExpr "LEFT" [t] _ -> do+ checkAnnsCount e annSet (1, 2, 1)+ t' <- fromExpression @Ty t+ let ta = firstAnn @TypeTag annSet+ let va = firstAnn @VarTag annSet+ let fa1 = firstAnn @FieldTag annSet+ let fa2 = secondAnn @FieldTag annSet+ pure $ LEFT ta va fa1 fa2 t'+ PrimExpr "RIGHT" [t] _ -> do+ checkAnnsCount e annSet (1, 2, 1)+ t' <- fromExpression @Ty t+ let ta = firstAnn @TypeTag annSet+ let va = firstAnn @VarTag annSet+ let fa1 = firstAnn @FieldTag annSet+ let fa2 = secondAnn @FieldTag annSet+ pure $ RIGHT ta va fa1 fa2 t'+ PrimExpr "IF_LEFT" [ops1, ops2] [] -> do+ ops1' <- fromExpression @([ExpandedOp]) ops1+ ops2' <- fromExpression @([ExpandedOp]) ops2+ pure $ IF_LEFT ops1' ops2'+ PrimExpr "NIL" [t] _ -> do+ checkAnnsCount e annSet (1, 0, 1)+ t' <- fromExpression @Ty t+ let va = firstAnn @VarTag annSet+ let ta = firstAnn @TypeTag annSet+ pure $ NIL ta va t'+ PrimExpr "CONS" [] anns -> mkInstrWithVarAnn CONS anns+ PrimExpr "IF_CONS" [ops1, ops2] [] -> do+ ops1' <- fromExpression @([ExpandedOp]) ops1+ ops2' <- fromExpression @([ExpandedOp]) ops2+ pure $ IF_CONS ops1' ops2'+ PrimExpr "SIZE" [] anns -> mkInstrWithVarAnn SIZE anns+ PrimExpr "EMPTY_SET" [t] _ -> do+ checkAnnsCount e annSet (1, 0, 1)+ t' <- fromExpression @Ty t+ let va = firstAnn @VarTag annSet+ let ta = firstAnn @TypeTag annSet+ pure $ EMPTY_SET ta va t'+ PrimExpr "EMPTY_MAP" [kt, vt] _ -> do+ checkAnnsCount e annSet (1, 0, 1)+ kt' <- fromExpression @Ty kt+ vt' <- fromExpression @Ty vt+ let va = firstAnn @VarTag annSet+ let ta = firstAnn @TypeTag annSet+ pure $ EMPTY_MAP ta va kt' vt'+ PrimExpr "EMPTY_BIG_MAP" [kt, vt] _ -> do+ checkAnnsCount e annSet (1, 0, 1)+ kt' <- fromExpression @Ty kt+ vt' <- fromExpression @Ty vt+ let va = firstAnn @VarTag annSet+ let ta = firstAnn @TypeTag annSet+ pure $ EMPTY_BIG_MAP ta va kt' vt'+ PrimExpr "MAP" [ops] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ ops' <- fromExpression @([ExpandedOp]) ops+ let va = firstAnn @VarTag annSet+ pure $ MAP va ops'+ PrimExpr "ITER" [ops] [] -> do+ ops' <- fromExpression @([ExpandedOp]) ops+ pure $ ITER ops'+ PrimExpr "MEM" [] anns -> mkInstrWithVarAnn MEM anns+ PrimExpr "GET" [] anns -> mkInstrWithVarAnn GET anns+ PrimExpr "GET" [n] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ n' <- intExprToWord n+ let va = firstAnn @VarTag annSet+ pure $ GETN va n'+ PrimExpr "UPDATE" [] anns -> mkInstrWithVarAnn UPDATE anns+ PrimExpr "UPDATE" [n] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ n' <- intExprToWord n+ let va = firstAnn @VarTag annSet+ pure $ UPDATEN va n'+ PrimExpr "GET_AND_UPDATE" [] anns ->+ mkInstrWithVarAnn GET_AND_UPDATE anns+ PrimExpr "IF" [ops1, ops2] [] -> do+ ops1' <- fromExpression @([ExpandedOp]) ops1+ ops2' <- fromExpression @([ExpandedOp]) ops2+ pure $ IF ops1' ops2'+ PrimExpr "LOOP" [ops] [] -> do+ ops' <- fromExpression @([ExpandedOp]) ops+ pure $ LOOP ops'+ PrimExpr "LOOP_LEFT" [ops] [] -> do+ ops' <- fromExpression @([ExpandedOp]) ops+ pure $ LOOP_LEFT ops'+ PrimExpr "LAMBDA" [inp, out, ops] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ inp' <- fromExpression @Ty inp+ out' <- fromExpression @Ty out+ ops' <- fromExpression @([ExpandedOp]) ops+ let va = firstAnn @VarTag annSet+ pure $ LAMBDA va inp' out' ops'+ PrimExpr "EXEC" [] anns -> mkInstrWithVarAnn EXEC anns+ PrimExpr "APPLY" [] anns -> mkInstrWithVarAnn APPLY anns+ PrimExpr "DIP" [ops] [] -> do+ ops' <- fromExpression @([ExpandedOp]) ops+ pure $ DIP ops'+ PrimExpr "DIP" [n, ops] [] -> do+ n' <- intExprToWord n+ ops' <- fromExpression @([ExpandedOp]) ops+ pure $ DIPN n' ops'+ PrimExpr "FAILWITH" [] [] -> pure FAILWITH+ PrimExpr "CAST" [t] _ -> do+ checkAnnsCount e annSet (0, 0, 1)+ t' <- fromExpression @Ty t+ let va = firstAnn @VarTag annSet+ pure $ CAST va t'+ PrimExpr "RENAME" [] anns -> mkInstrWithVarAnn RENAME anns+ PrimExpr "PACK" [] anns -> mkInstrWithVarAnn PACK anns+ PrimExpr "UNPACK" [t] _ -> do+ checkAnnsCount e annSet (1, 0, 1)+ t' <- fromExpression @Ty t+ let ta = firstAnn @TypeTag annSet+ let va = firstAnn @VarTag annSet+ pure $ UNPACK ta va t'+ PrimExpr "CONCAT" [] anns -> mkInstrWithVarAnn CONCAT anns+ PrimExpr "SLICE" [] anns -> mkInstrWithVarAnn SLICE anns+ PrimExpr "ISNAT" [] anns -> mkInstrWithVarAnn ISNAT anns+ PrimExpr "ADD" [] anns -> mkInstrWithVarAnn ADD anns+ PrimExpr "SUB" [] anns -> mkInstrWithVarAnn SUB anns+ PrimExpr "MUL" [] anns -> mkInstrWithVarAnn MUL anns+ PrimExpr "EDIV" [] anns -> mkInstrWithVarAnn EDIV anns+ PrimExpr "ABS" [] anns -> mkInstrWithVarAnn ABS anns+ PrimExpr "NEG" [] anns -> mkInstrWithVarAnn NEG anns+ PrimExpr "LSL" [] anns -> mkInstrWithVarAnn LSL anns+ PrimExpr "LSR" [] anns -> mkInstrWithVarAnn LSR anns+ PrimExpr "OR" [] anns -> mkInstrWithVarAnn OR anns+ PrimExpr "AND" [] anns -> mkInstrWithVarAnn AND anns+ PrimExpr "XOR" [] anns -> mkInstrWithVarAnn XOR anns+ PrimExpr "NOT" [] anns -> mkInstrWithVarAnn NOT anns+ PrimExpr "COMPARE" [] anns -> mkInstrWithVarAnn COMPARE anns+ PrimExpr "EQ" [] anns -> mkInstrWithVarAnn Untyped.EQ anns+ PrimExpr "NEQ" [] anns -> mkInstrWithVarAnn NEQ anns+ PrimExpr "LT" [] anns -> mkInstrWithVarAnn Untyped.LT anns+ PrimExpr "GT" [] anns -> mkInstrWithVarAnn Untyped.GT anns+ PrimExpr "LE" [] anns -> mkInstrWithVarAnn LE anns+ PrimExpr "GE" [] anns -> mkInstrWithVarAnn GE anns+ PrimExpr "INT" [] anns -> mkInstrWithVarAnn INT anns+ PrimExpr "SELF" [] _ ->+ let fa = firstAnn @FieldTag annSet+ va = firstAnn @VarTag annSet+ in checkAnnsCount e annSet (0, 1, 1) $> SELF va fa+ PrimExpr "CONTRACT" [t] _ -> do+ checkAnnsCount e annSet (0, 1, 1)+ t' <- fromExpression @Ty t+ let va = firstAnn @VarTag annSet+ let fa = firstAnn @FieldTag annSet+ pure $ CONTRACT va fa t'+ PrimExpr "TRANSFER_TOKENS" [] anns ->+ mkInstrWithVarAnn TRANSFER_TOKENS anns+ PrimExpr "SET_DELEGATE" [] anns ->+ mkInstrWithVarAnn SET_DELEGATE anns+ PrimExpr "CREATE_CONTRACT" [c] _ -> do+ checkAnnsCount e annSet (0, 0, 2)+ c' <- fromExpression @Untyped.Contract c+ let va1 = firstAnn @VarTag annSet+ let va2 = secondAnn @VarTag annSet+ pure $ CREATE_CONTRACT va1 va2 c'+ PrimExpr "IMPLICIT_ACCOUNT" [] anns ->+ mkInstrWithVarAnn IMPLICIT_ACCOUNT anns+ PrimExpr "NOW" [] anns -> mkInstrWithVarAnn NOW anns+ PrimExpr "AMOUNT" [] anns -> mkInstrWithVarAnn AMOUNT anns+ PrimExpr "BALANCE" [] anns -> mkInstrWithVarAnn BALANCE anns+ PrimExpr "VOTING_POWER" [] anns ->+ mkInstrWithVarAnn VOTING_POWER anns+ PrimExpr "TOTAL_VOTING_POWER" [] anns ->+ mkInstrWithVarAnn TOTAL_VOTING_POWER anns+ PrimExpr "CHECK_SIGNATURE" [] anns ->+ mkInstrWithVarAnn CHECK_SIGNATURE anns+ PrimExpr "SHA256" [] anns -> mkInstrWithVarAnn SHA256 anns+ PrimExpr "SHA512" [] anns -> mkInstrWithVarAnn SHA512 anns+ PrimExpr "BLAKE2B" [] anns -> mkInstrWithVarAnn BLAKE2B anns+ PrimExpr "SHA3" [] anns -> mkInstrWithVarAnn SHA3 anns+ PrimExpr "KECCAK" [] anns -> mkInstrWithVarAnn KECCAK anns+ PrimExpr "HASH_KEY" [] anns -> mkInstrWithVarAnn HASH_KEY anns+ PrimExpr "PAIRING_CHECK" [] anns ->+ mkInstrWithVarAnn PAIRING_CHECK anns+ PrimExpr "SOURCE" [] anns -> mkInstrWithVarAnn SOURCE anns+ PrimExpr "SENDER" [] anns -> mkInstrWithVarAnn SENDER anns+ PrimExpr "ADDRESS" [] anns -> mkInstrWithVarAnn ADDRESS anns+ PrimExpr "CHAIN_ID" [] anns -> mkInstrWithVarAnn CHAIN_ID anns+ PrimExpr "LEVEL" [] anns -> mkInstrWithVarAnn LEVEL anns+ PrimExpr "SELF_ADDRESS" [] anns ->+ mkInstrWithVarAnn SELF_ADDRESS anns+ PrimExpr "NEVER" [] [] -> pure NEVER+ PrimExpr "TICKET" [] anns -> mkInstrWithVarAnn TICKET anns+ PrimExpr "READ_TICKET" [] anns ->+ mkInstrWithVarAnn READ_TICKET anns+ PrimExpr "SPLIT_TICKET" [] anns ->+ mkInstrWithVarAnn SPLIT_TICKET anns+ PrimExpr "JOIN_TICKETS" [] anns ->+ mkInstrWithVarAnn JOIN_TICKETS anns+ _ -> Left $ FromExpressionError e "Expected an instruction"++ where+ intExprToWord :: Expression -> Either FromExpressionError Word+ intExprToWord n = do+ v <- fromExpression @(Value 'TInt) n+ case v of+ VInt n' -> maybeToRight (FromExpressionError n "Value is out of bounds")+ (toIntegralSized @Integer @Word n')++ mkInstrWithVarAnn+ :: (VarAnn -> ExpandedInstr)+ -> [Annotation]+ -> Either FromExpressionError ExpandedInstr+ mkInstrWithVarAnn ctor anns =+ let annSet = toAnnSet anns+ va = firstAnn @VarTag annSet+ in checkAnnsCount e annSet (0, 0, 1) $> ctor va++ getAnnSet :: Expression -> AnnotationSet+ getAnnSet = \case+ PrimExpr _ _ anns -> toAnnSet anns+ _ -> emptyAnnSet+ instance FromExpression Untyped.Contract where- fromExpression =- first FromExpressionError . launchGet decodeContract .- LBS.fromStrict . encodeExpression+ fromExpression blocks = case blocks of+ ExpressionSeq [b1, b2, b3] -> do+ b1' <- exprToCB b1+ b2' <- exprToCB b2+ b3' <- exprToCB b3+ maybeToRight (FromExpressionError blocks fullErrorMsg)+ (orderContractBlock (b1', b2', b3'))+ expr -> Left $ FromExpressionError expr fullErrorMsg+ where+ exprToCB+ :: Expression+ -> Either FromExpressionError (ContractBlock ExpandedOp)+ exprToCB e = case e of+ PrimExpr "parameter" args anns -> mkCbParam e args anns+ PrimExpr "storage" args anns -> mkCBStorage e args anns+ PrimExpr "code" args anns -> mkCBCode e args anns+ _ -> Left $ FromExpressionError e fullErrorMsg -instance FromExpression Untyped.Ty where- fromExpression =- first FromExpressionError .- launchGet decodeType .- LBS.fromStrict .- encodeExpression+ mkCbParam+ :: Expression+ -> [Expression]+ -> [Annotation]+ -> Either FromExpressionError (ContractBlock ExpandedOp)+ mkCbParam e args anns = case (args, anns) of+ ([p], []) -> do+ let annSet = toAnnSet (p ^. _ExpressionPrim . mpaAnnotsL)+ let rootAnn = firstAnn @FieldTag annSet+ unless (secondAnn @FieldTag annSet == noAnn) $+ Left $ FromExpressionError p+ "Expected parameter with at most 1 root annotation"+ p' <- fromExpression @Ty+ (p & _ExpressionPrim . mpaAnnotsL %~ filter (not . isAnnotationField))+ pure $ CBParam $ Untyped.ParameterType p' rootAnn+ _ -> Left $ FromExpressionError e+ "Expected 'parameter' block without annotations and exactly 1 argument" + mkCBStorage+ :: Expression+ -> [Expression]+ -> [Annotation]+ -> Either FromExpressionError (ContractBlock ExpandedOp)+ mkCBStorage e args anns = case (args, anns) of+ ([s], []) -> do+ s' <- fromExpression @Ty s+ pure $ CBStorage s'+ _ -> Left $ FromExpressionError e+ "Expected 'storage' block without annotations and exactly 1 argument"++ mkCBCode+ :: Expression+ -> [Expression]+ -> [Annotation]+ -> Either FromExpressionError (ContractBlock ExpandedOp)+ mkCBCode e args anns = case (args, anns) of+ ([ops], []) -> do+ ops' <- fromExpression @([ExpandedOp]) ops+ pure $ CBCode ops'+ _ -> Left $ FromExpressionError e+ "Expected 'code' block without annotations"++ fullErrorMsg = "Expected contract expression to have exactly 3 " <>+ "sub-expressions ('parameter', 'storage' and 'code')"+++instance FromExpression Untyped.T where+ fromExpression e = case e of+ PrimExpr "key" [] [] -> pure Untyped.TKey+ PrimExpr "unit" [] [] -> pure Untyped.TUnit+ PrimExpr "signature" [] [] -> pure Untyped.TSignature+ PrimExpr "chain_id" [] [] -> pure Untyped.TChainId+ PrimExpr "option" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.TOption arg'+ PrimExpr "list" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.TList arg'+ PrimExpr "set" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.TSet arg'+ PrimExpr "operation" [] [] -> pure Untyped.TOperation+ PrimExpr "contract" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.TContract arg'+ PrimExpr "ticket" [arg] [] -> do+ arg' <- fromExpression arg+ pure $ Untyped.TTicket arg'+ PrimExpr "or" [arg1, arg2] [] -> do+ let as1 = toAnnSet $ arg1 ^. _ExpressionPrim . mpaAnnotsL+ let as2 = toAnnSet $ arg2 ^. _ExpressionPrim . mpaAnnotsL+ checkAnnsCount e as1 (1, 1, 0)+ checkAnnsCount e as2 (1, 1, 0)+ let fa1 = firstAnn @FieldTag as1+ let fa2 = firstAnn @FieldTag as2+ l <- fromExpression $ removeAnns arg1 isAnnotationField+ r <- fromExpression $ removeAnns arg2 isAnnotationField+ pure $ Untyped.TOr fa1 fa2 l r+ PrimExpr "pair" [arg1, arg2] [] -> do+ let as1 = toAnnSet $ arg1 ^. _ExpressionPrim . mpaAnnotsL+ let as2 = toAnnSet $ arg2 ^. _ExpressionPrim . mpaAnnotsL+ checkAnnsCount e as1 (1, 1, 1)+ checkAnnsCount e as2 (1, 1, 1)+ let fa1 = firstAnn @FieldTag as1+ let fa2 = firstAnn @FieldTag as2+ let va1 = firstAnn @VarTag as1+ let va2 = firstAnn @VarTag as2+ l <- fromExpression $ removeAnns arg1+ (liftA2 (||) isAnnotationField isAnnotationVariable)+ r <- fromExpression $ removeAnns arg2+ (liftA2 (||) isAnnotationField isAnnotationVariable)+ pure $ Untyped.TPair fa1 fa2 va1 va2 l r+ PrimExpr "pair" args [] ->+ case (nonEmpty args) >>= forbidSingletonList of+ Nothing -> Left $ FromExpressionError e+ "Expected a pair with at least 2 arguments"+ Just args' -> fromExpression $ seqToPairExpr args' "pair"+ PrimExpr "lambda" args [] -> mkDoubleParamType Untyped.TLambda args e+ "Expected a lambda with input and output types"+ PrimExpr "map" args [] -> mkDoubleParamType Untyped.TMap args e+ "Expected a map with key and value types"+ PrimExpr "big_map" args [] -> mkDoubleParamType Untyped.TBigMap args e+ "Expected a big_map with key and value types"+ PrimExpr "int" [] [] -> pure Untyped.TInt+ PrimExpr "nat" [] [] -> pure Untyped.TNat+ PrimExpr "string" [] [] -> pure Untyped.TString+ PrimExpr "bytes" [] [] -> pure Untyped.TBytes+ PrimExpr "mutez" [] [] -> pure Untyped.TMutez+ PrimExpr "bool" [] [] -> pure Untyped.TBool+ PrimExpr "key_hash" [] [] -> pure Untyped.TKeyHash+ PrimExpr "bls12_381_fr" [] [] -> pure Untyped.TBls12381Fr+ PrimExpr "bls12_381_g1" [] [] -> pure Untyped.TBls12381G1+ PrimExpr "bls12_381_g2" [] [] -> pure Untyped.TBls12381G2+ PrimExpr "timestamp" [] [] -> pure Untyped.TTimestamp+ PrimExpr "address" [] [] -> pure Untyped.TAddress+ PrimExpr "never" [] [] -> pure Untyped.TNever+ _ -> Left $ FromExpressionError e "Expected a type"+ where+ mkDoubleParamType+ :: (Ty -> Ty -> Untyped.T)+ -> [Expression]+ -> Expression+ -> Text+ -> Either FromExpressionError Untyped.T+ mkDoubleParamType ctor args expr msg = do+ case args of+ [arg1, arg2] -> do+ arg1' <- fromExpression arg1+ arg2' <- fromExpression arg2+ pure $ ctor arg1' arg2'+ _ -> Left $ FromExpressionError expr msg++ removeAnns :: Expression -> (Annotation -> Bool) -> Expression+ removeAnns expr p =+ expr & _ExpressionPrim . mpaAnnotsL %~ filter (not . p)++instance FromExpression Ty where+ fromExpression e = case e of+ PrimExpr primName args anns -> do+ let annSet = toAnnSet anns+ let ta = firstAnn @TypeTag annSet+ when (secondAnn @TypeTag annSet /= noAnn) $+ Left $ FromExpressionError e+ "Expected expression with at most 1 type annotation"+ t <- fromExpression @Untyped.T $ PrimExpr primName args $ filter+ (not . isAnnotationType) anns+ pure $ Ty t ta+ _ -> Left $ FromExpressionError e "Expected a type"+ instance FromExpression T where fromExpression = second fromUType . fromExpression @Untyped.Ty -- Note: we should generalize this to work for any instruction, -- not just lambdas (i.e. instructions with one input and one output).-instance (KnownT inp, KnownT out) => FromExpression (Instr '[inp] '[out]) where+instance (SingI inp, SingI out) => FromExpression (Instr '[inp] '[out]) where fromExpression expr = fromExpression @(Value ('TLambda inp out)) expr <&> \case VLam instr -> rfAnyInstr instr++----------------------------------------------------------------------------+-- Helpers+----------------------------------------------------------------------------++-- | Converts a sequence of expression to the right combed pair.+seqToPairExpr :: NonEmpty Expression -> Text -> Expression+seqToPairExpr e name = foldr1 (\x xs -> PrimExpr name [x, xs] []) e++-- | Adds annotations to the expression, after removing empty annotations+-- at the end of each list.+addTrimmedAnns+ :: Expression+ -> [TypeAnn]+ -> [FieldAnn]+ -> [VarAnn]+ -> Expression+addTrimmedAnns e tas fas vas =+ e & _ExpressionPrim . mpaAnnotsL <>~ mkAnns tas fas vas++-- | Inserts the root annotation into the contract parameter.+insertRootAnn :: HasCallStack => Expression -> RootAnn -> Expression+insertRootAnn expr rootAnn = case expr of+ ExpressionPrim p+ -- The order of annotations is important iff there are+ -- multiple annotations of the same kind or there are+ -- other kinds of annotations in the list.+ -- Prepending root field annotation is okay because+ -- there can not be more than one root annotation.+ | rootAnn /= noAnn -> ExpressionPrim p+ { mpaAnnots = AnnotationField rootAnn : mpaAnnots p+ }+ | otherwise -> expr+ -- Currently this error can't happen because parameter type+ -- must be a Micheline primitive. If it ever changes, we+ -- would like to notice it ASAP and update this place.+ _ -> error $ "parameter is not a primitive: " <> show expr++-- | Checks for a given expression that the number of annotations+-- of each type in it doesn't exceed the specified threshold.+checkAnnsCount+ :: Expression+ -> AnnotationSet+ -> (Int, Int, Int)+ -> Either FromExpressionError ()+checkAnnsCount e annSet maxCount@(maxTas, maxFas, maxVas) =+ let actualCount@(tasCnt, fasCnt, vasCnt) = annsCount annSet+ in unless (actualCount <= maxCount) $+ Left $ FromExpressionError e $ pretty $ unlinesF+ [ "Expected at most"+ , indentF 2 $ build maxTas <> " type annotations,"+ , indentF 2 $ build maxFas <> " field annotations,"+ , indentF 2 $ build maxVas <> " variable annotations"+ , "but found:"+ , indentF 2 $ build tasCnt <> " type annotations,"+ , indentF 2 $ build fasCnt <> " field annotations,"+ , indentF 2 $ build vasCnt <> " variable annotations."+ ]++forbidSingletonList :: NonEmpty a -> Maybe (NonEmpty a)+forbidSingletonList = \case+ _ :| [] -> Nothing+ x -> Just x
src/Morley/Micheline/Expression.hs view
@@ -7,16 +7,34 @@ -- | Module that defines Expression type, its related types -- and its JSON instance. module Morley.Micheline.Expression- ( Annotation(..)- , Expression(..)+ ( Expression(.., PrimExpr) , MichelinePrimAp(..) , MichelinePrimitive(..) , michelsonPrimitive++ , Annotation (..) , annotToText , annotFromText+ , isAnnotationField+ , isAnnotationType+ , isAnnotationVariable+ , isNoAnn+ , mkAnns+ , toAnnSet++ -- * Prisms+ , _ExpressionPrim+ , _AnnotationField+ , _AnnotationVariable+ , _AnnotationType++ -- * Lenses+ , mpaAnnotsL ) where import Control.Lens (Plated)+import Control.Lens.TH+ import Data.Aeson (FromJSON, ToJSON, object, parseJSON, toEncoding, toJSON, withObject, withText, (.!=), (.:), (.:?), (.=))@@ -28,8 +46,10 @@ import qualified Data.Text as T (uncons) import Fmt (Buildable(..), pretty, (+|), (|+)) +import qualified Michelson.Untyped as U import Michelson.Untyped.Annotation- (FieldAnn, FieldTag, KnownAnnTag(..), TypeAnn, TypeTag, VarAnn, VarTag, annPrefix, mkAnnotation)+ (FieldAnn, FieldTag, KnownAnnTag(..), AnnotationSet(..), TypeAnn, TypeTag,+ VarAnn, VarTag, annPrefix, mkAnnotation, minimizeAnnSet, fullAnnSet) import Morley.Micheline.Json (StringEncode(StringEncode, unStringEncode)) import Tezos.Crypto (encodeBase58Check) import Util.ByteString (HexJSONByteString(..))@@ -87,10 +107,14 @@ -- JSON encoding compatibility. | ExpressionString Text | ExpressionBytes ByteString- | ExpressionSeq (Seq Expression)+ | ExpressionSeq [Expression] | ExpressionPrim MichelinePrimAp deriving stock (Eq, Show, Data) +pattern PrimExpr :: Text -> [Expression] -> [Annotation] -> Expression+pattern PrimExpr primName args anns =+ ExpressionPrim (MichelinePrimAp (MichelinePrimitive primName) args anns)+ instance Plated Expression instance Buildable Expression where@@ -99,15 +123,13 @@ ExpressionString s -> build s ExpressionBytes b -> build $ encodeBase58Check b- ExpressionSeq s -> "(" +| buildSeq build s |+ ")"+ ExpressionSeq s -> "(" +| buildList build s |+ ")" ExpressionPrim (MichelinePrimAp (MichelinePrimitive text) s annots) -> text <> " " |+ "(" +|- buildSeq build s +| ") " +|- buildSeq (build . annotToText) annots+ buildList build s +| ") " +|+ buildList (build . annotToText) annots where- buildSeq buildElem =- mconcat . intersperse ", " . map- buildElem . toList+ buildList buildElem = mconcat . intersperse ", " . map buildElem data Annotation = AnnotationType TypeAnn@@ -117,21 +139,21 @@ data MichelinePrimAp = MichelinePrimAp { mpaPrim :: MichelinePrimitive- , mpaArgs :: Seq Expression- , mpaAnnots :: Seq Annotation+ , mpaArgs :: [Expression]+ , mpaAnnots :: [Annotation] } deriving stock (Eq, Show, Data) instance FromJSON MichelinePrimAp where parseJSON = withObject "Prim" $ \v -> MichelinePrimAp <$> v .: "prim"- <*> v .:? "args" .!= mempty- <*> v .:? "annots" .!= mempty+ <*> v .:? "args" .!= []+ <*> v .:? "annots" .!= [] instance ToJSON MichelinePrimAp where toJSON MichelinePrimAp {..} = object $ catMaybes [ Just ("prim" .= mpaPrim)- , if mpaArgs == mempty then Nothing else Just ("args" .= mpaArgs)- , if mpaAnnots == mempty then Nothing else Just ("annots" .= mpaAnnots)+ , if null mpaArgs then Nothing else Just ("args" .= mpaArgs)+ , if null mpaAnnots then Nothing else Just ("annots" .= mpaAnnots) ] annotFromText :: forall m. MonadFail m => Text -> m Annotation@@ -156,6 +178,41 @@ AnnotationVariable n -> pretty n AnnotationField n -> pretty n +mkAnns :: [TypeAnn] -> [FieldAnn] -> [VarAnn] -> [Annotation]+mkAnns tas fas vas =+ let minAnnSet = minimizeAnnSet $ fullAnnSet tas fas vas+ in (AnnotationType <$> asTypes minAnnSet) <>+ (AnnotationField <$> asFields minAnnSet) <>+ (AnnotationVariable <$> asVars minAnnSet)++isAnnotationField :: Annotation -> Bool+isAnnotationField = \case+ AnnotationField _ -> True+ _ -> False++isAnnotationVariable :: Annotation -> Bool+isAnnotationVariable = \case+ AnnotationVariable _ -> True+ _ -> False++isAnnotationType :: Annotation -> Bool+isAnnotationType = \case+ AnnotationType _ -> True+ _ -> False++isNoAnn :: Annotation -> Bool+isNoAnn = \case+ AnnotationVariable (U.Annotation "") -> True+ AnnotationField (U.Annotation "") -> True+ AnnotationType (U.Annotation "") -> True+ _ -> False++toAnnSet :: [Annotation] -> AnnotationSet+toAnnSet = foldMap $ \case+ AnnotationType a -> U.singleAnnSet a+ AnnotationField a -> U.singleAnnSet a+ AnnotationVariable a -> U.singleAnnSet a+ instance FromJSON Annotation where parseJSON = withText "Annotation" annotFromText @@ -182,3 +239,7 @@ toEncoding (ExpressionString x) = Aeson.pairs (Aeson.pair "string" (toEncoding x)) toEncoding (ExpressionInt x) = Aeson.pairs (Aeson.pair "int" (toEncoding $ StringEncode x)) toEncoding (ExpressionBytes x) = Aeson.pairs (Aeson.pair "bytes" (toEncoding $ HexJSONByteString x))++makePrisms ''Expression+makePrisms ''Annotation+makeLensesFor [("mpaAnnots", "mpaAnnotsL")] ''MichelinePrimAp
src/Tezos/Address.hs view
@@ -4,16 +4,16 @@ -- | Address in Tezos. +{-# LANGUAGE DeriveLift #-}+ module Tezos.Address ( ContractHash (..) , Address (..) , mkKeyAddress , detGenKeyAddress - , OperationHash (..) , OriginationIndex (..) , GlobalCounter(..)- , mkContractAddress , mkContractHashHack -- * Formatting@@ -25,6 +25,7 @@ , parseAddressRaw , parseContractHash , parseAddress+ , ta , unsafeParseAddressRaw , unsafeParseAddress , unsafeParseContractHash@@ -34,19 +35,25 @@ import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encoding as Aeson import qualified Data.Aeson.Types as AesonTypes-import Data.Binary.Put (putInt32be, putWord64be, runPut) import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as BSL+import Data.Text (strip) import Fmt (Buildable(build), hexF, pretty)+import Instances.TH.Lift ()+import qualified Language.Haskell.TH.Quote as TH+import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax (Lift)+import Text.PrettyPrint.Leijen.Text ((<+>), backslash, dquotes, int, parens) +import Michelson.Printer.Util (RenderDoc (..), buildRenderDoc, renderAnyBuildable) import Michelson.Text import Tezos.Crypto import Util.CLI+import Util.TypeLits -- TODO: we should probably have a `Hash` type. -- | Hash of origination command for some contract. newtype ContractHash = ContractHash ByteString- deriving stock (Show, Eq, Ord, Generic)+ deriving stock (Show, Eq, Ord, Generic, Lift) instance NFData ContractHash @@ -63,7 +70,7 @@ -- ^ `tz` address which is a hash of a public key. | ContractAddress ContractHash -- ^ `KT` address which corresponds to a callable contract.- deriving stock (Show, Eq, Ord, Generic)+ deriving stock (Show, Eq, Ord, Generic, Lift) instance NFData Address @@ -76,12 +83,6 @@ detGenKeyAddress :: ByteString -> Address detGenKeyAddress = mkKeyAddress . toPublic . detSecretKey -newtype OperationHash = OperationHash- { unOperationHash :: ByteString- }- deriving stock (Show, Eq, Ord, Generic)- deriving anyclass (NFData)- -- | Represents the network's global counter. -- -- When a new contract is created (either via a "global" origination operation or@@ -118,38 +119,6 @@ deriving stock (Show, Eq, Ord, Generic) deriving anyclass (NFData) --- | Compute address of a contract from its origination operation, origination index and global counter.------ However, in real Tezos encoding of the operation is more than just 'OriginationOperation'.--- There an Operation has several more meta-fields plus a big sum-type of all possible operations.------ See here: https://gitlab.com/tezos/tezos/-/blob/f57c50e3a657956d69a1699978de9873c98f0018/src/proto_006_PsCARTHA/lib_protocol/operation_repr.ml#L78------ What is important is that one (big) Operation may lead to origination of multiple contracts. That--- is why contract address is constructed from hash of the operation that originated and of index--- of the contract's origination in the execution of that operation.------ In other words, contract hash is calculated as the blake2b160 (20-byte) hash of--- origination operation hash + int32 origination index + word64 global counter.------ In Morley we do not yet support full encoding of Tezos Operations, therefore we choose--- to generate contract addresses in a simplified manner.------ Namely, we encode 'OriginationOperation' as we can and concat it with the origination index--- and the global counter.--- Then we take 'blake2b160' hash of the resulting bytes and consider it to be the contract's--- address.-mkContractAddress- :: OperationHash- -> OriginationIndex- -> GlobalCounter- -> Address-mkContractAddress (OperationHash opHash) (OriginationIndex idx) (GlobalCounter counter) =- ContractAddress- $ ContractHash- $ blake2b160- $ opHash <> BSL.toStrict (runPut $ putInt32be idx >> putWord64be counter)- -- | Create a dummy 'ContractHash' value by hashing given 'ByteString'. -- -- Use in tests **only**.@@ -176,7 +145,7 @@ ContractAddress h -> formatContractHash h mformatAddress :: Address -> MText-mformatAddress = mkMTextUnsafe . formatAddress+mformatAddress = unsafeMkMText . formatAddress instance Buildable Address where build = build . formatAddress@@ -192,16 +161,18 @@ instance NFData ParseAddressError instance Buildable ParseAddressError where- build =+ build = buildRenderDoc++instance RenderDoc ParseAddressError where+ renderDoc context = \case ParseAddressWrongBase58Check -> "Wrong base58check format" ParseAddressBothFailed pkErr contractErr -> mconcat- [ "Address is neither `KeyAddress` ("- , build pkErr- , "), nor `ContractAddress` ("- , build contractErr- , ")"+ [ "Address is neither `KeyAddress` "+ , parens $ renderDoc context pkErr+ , ", nor `ContractAddress` "+ , parens $ renderDoc context contractErr ] -- | Parse an address from its human-readable textual representation@@ -226,16 +197,19 @@ instance NFData ParseAddressRawError -instance Buildable ParseAddressRawError where- build =+instance RenderDoc ParseAddressRawError where+ renderDoc _ = \case ParseAddressRawInvalidPrefix prefix ->- "Invalid prefix for raw address \"" <> hexF prefix <> "\" provided"- ParseAddressRawWrongSize addr -> "Given raw address " <>- hexF addr <> " has invalid length " <> show (length addr)- ParseAddressRawMalformedSeparator addr -> "Given raw address " <> hexF addr <>- " does not end with \"\\00\""+ "Invalid prefix for raw address" <+> (dquotes $ renderAnyBuildable $ hexF prefix) <+> "provided"+ ParseAddressRawWrongSize addr -> "Given raw address+" <+>+ (renderAnyBuildable $ hexF addr) <+> "has invalid length" <+> int (length addr)+ ParseAddressRawMalformedSeparator addr -> "Given raw address+" <+> (renderAnyBuildable $ hexF addr) <+>+ "does not end with" <+> dquotes (backslash <> "00") +instance Buildable ParseAddressRawError where+ build = buildRenderDoc+ -- | Parse the given address in its raw byte form used by Tezos -- (e.g "01521139f84791537d54575df0c74a8084cc68861c00")) . Or fail otherwise -- if it's invalid.@@ -275,15 +249,18 @@ instance NFData ParseContractAddressError instance Buildable ParseContractAddressError where- build =+ build = buildRenderDoc++instance RenderDoc ParseContractAddressError where+ renderDoc _ = \case ParseContractAddressWrongBase58Check -> "Wrong base58check format" ParseContractAddressWrongSize bs ->- "Wrong size for a contract address: " <> hexF bs <>- " (" <> build (length bs) <> ")"+ "Wrong size for a contract address:" <+> (renderAnyBuildable $ hexF bs) <+>+ (parens $ int (length bs)) ParseContractAddressWrongPrefix prefix ->- "Invalid prefix \"" <> hexF prefix <> "\" provided"+ "Invalid prefix" <+> (dquotes $ renderAnyBuildable $ hexF prefix) <+> "provided" parseContractHash :: Text -> Either ParseContractAddressError ContractHash parseContractHash text =@@ -294,6 +271,32 @@ Left ParseContractAddressWrongBase58Check Right bs | length bs == contractHashLengthBytes -> Right (ContractHash bs) | otherwise -> Left $ ParseContractAddressWrongSize bs++-- | QuasyQuoter for constructing Tezos addresses.+--+-- Validity of result will be checked at compile time.+ta :: TH.QuasiQuoter+ta = TH.QuasiQuoter+ { TH.quoteExp = \s ->+ case parseAddress . strip $ toText s of+ Left err -> fail $ pretty err+ Right addr -> TH.lift addr+ , TH.quotePat = \_ ->+ fail "Cannot use this QuasyQuotation at pattern position"+ , TH.quoteType = \_ ->+ fail "Cannot use this QuasyQuotation at type position"+ , TH.quoteDec = \_ ->+ fail "Cannot use this QuasyQuotation at declaration position"+ }+++instance+ TypeError ('Text "There is no instance defined for (IsString Address)" ':$$:+ 'Text "Consider using QuasiQuotes: `[ta|some text...|]`"+ ) =>+ IsString Address where+ fromString = error "impossible"+ ---------------------------------------------------------------------------- -- Unsafe
src/Tezos/Core.hs view
@@ -7,7 +7,7 @@ module Tezos.Core ( -- * Mutez- Mutez (unMutez)+ Mutez (..) , mkMutez , mkMutez' , unsafeMkMutez@@ -42,7 +42,7 @@ -- * ChainId , ChainId (..) , mkChainId- , mkChainIdUnsafe+ , unsafeMkChainId , dummyChainId , formatChainId , mformatChainId@@ -77,19 +77,19 @@ ---------------------------------------------------------------------------- -- | Mutez is a wrapper over integer data type. 1 mutez is 1 token (μTz).-newtype Mutez = Mutez+newtype Mutez = UnsafeMutez { unMutez :: Word64 } deriving stock (Show, Eq, Ord, Data, Generic) deriving newtype Enum instance Buildable Mutez where- build (Mutez w) = build w <> " μꜩ"+ build (UnsafeMutez w) = build w <> " μꜩ" instance Bounded Mutez where- minBound = Mutez 0+ minBound = UnsafeMutez 0 -- 2⁶³ - 1 -- This value was checked against the reference implementation.- maxBound = Mutez 9223372036854775807+ maxBound = UnsafeMutez 9223372036854775807 instance HasCLReader Mutez where getReader = maybe (readerError "Invalid mutez") pure . mkMutez =<< Opt.auto@@ -100,7 +100,7 @@ -- | Safely create 'Mutez' checking for overflow. mkMutez :: Word64 -> Maybe Mutez mkMutez n- | n <= unMutez maxBound = Just (Mutez n)+ | n <= unMutez maxBound = Just (UnsafeMutez n) | otherwise = Nothing {-# INLINE mkMutez #-} @@ -146,7 +146,7 @@ -- subtrahend is greater than the minuend, and 'Just' otherwise. subMutez :: Mutez -> Mutez -> Maybe Mutez subMutez (unMutez -> a) (unMutez -> b)- | a >= b = Just (Mutez (a - b))+ | a >= b = Just (UnsafeMutez (a - b)) | otherwise = Nothing {-# INLINE subMutez #-} @@ -159,7 +159,7 @@ -- 'Nothing' in case of overflow. mulMutez :: Integral a => Mutez -> a -> Maybe Mutez mulMutez (unMutez -> a) b- | res <= toInteger (unMutez maxBound) = Just (Mutez (fromInteger res))+ | res <= toInteger (unMutez maxBound) = Just (UnsafeMutez (fromInteger res)) | otherwise = Nothing where res = toInteger a * toInteger b@@ -181,7 +181,7 @@ | otherwise = Just $ bimap toMutez' toMutez' (a `divMod` b) where toMutez' :: Integer -> Mutez- toMutez' = Mutez . fromInteger+ toMutez' = UnsafeMutez . fromInteger -- | Convert mutez to signed number. --@@ -190,10 +190,10 @@ mutezToInt64 = fromIntegral . unMutez zeroMutez :: Mutez-zeroMutez = Mutez minBound+zeroMutez = UnsafeMutez minBound oneMutez :: Mutez-oneMutez = Mutez 1+oneMutez = UnsafeMutez 1 -- | -- >>> putTextLn $ prettyTez (toMutez 420)@@ -314,7 +314,7 @@ -- Use case: multisig contract, for instance, now includes chain ID into -- signed data "in order to add extra replay protection between the main -- chain and the test chain".-newtype ChainId = ChainIdUnsafe { unChainId :: ByteString }+newtype ChainId = UnsafeChainId { unChainId :: ByteString } deriving stock (Show, Eq, Ord, Generic) instance NFData ChainId@@ -322,16 +322,16 @@ -- | Construct chain ID from raw bytes. mkChainId :: ByteString -> Maybe ChainId mkChainId bs =- guard (length bs == chainIdLength) $> ChainIdUnsafe bs+ guard (length bs == chainIdLength) $> UnsafeChainId bs -- | Construct chain ID from raw bytes or fail otherwise. -- Expects exactly 4 bytes.-mkChainIdUnsafe :: HasCallStack => ByteString -> ChainId-mkChainIdUnsafe = fromMaybe (error "Bad chain id") . mkChainId+unsafeMkChainId :: HasCallStack => ByteString -> ChainId+unsafeMkChainId = fromMaybe (error "Bad chain id") . mkChainId -- | Identifier of a pseudo network. dummyChainId :: ChainId-dummyChainId = ChainIdUnsafe "\0\0\0\0"+dummyChainId = UnsafeChainId "\0\0\0\0" -- | Pretty print 'ChainId' as it is displayed e.g. in -- @tezos-client rpc get /chains/main/chain_id@ call.@@ -341,7 +341,7 @@ formatChainId (unChainId -> bs) = encodeBase58Check (chainIdPrefix <> bs) mformatChainId :: ChainId -> MText-mformatChainId = mkMTextUnsafe . formatChainId+mformatChainId = unsafeMkMText . formatChainId instance Buildable ChainId where build = build . formatChainId
src/Tezos/Crypto.hs view
@@ -32,6 +32,8 @@ -- <https://gitlab.com/tezos/tezos/blob/c52ee69231c5ae4d9cec1f3c8aba0c3573922e2a/src/lib_crypto/base58.ml>) -- and checked manually. Existing tests confirm they are correct. +{-# LANGUAGE DeriveLift #-}+ module Tezos.Crypto ( -- * Cryptographic primitive types PublicKey (..)@@ -67,7 +69,7 @@ , formatKeyHash , mformatKeyHash , parseKeyHash- , parseKeyHashUnsafe+ , unsafeParseKeyHash , parseKeyHashRaw , keyHashLengthBytes , formatSecretKey@@ -102,6 +104,8 @@ import qualified Data.ByteString.Lazy as LBS import qualified Data.Text as T import Fmt (Buildable, build, hexF, pretty)+import Instances.TH.Lift ()+import Language.Haskell.TH.Syntax (Lift) import Michelson.Text import qualified Tezos.Crypto.BLS12381 as BLS12381@@ -313,7 +317,7 @@ PublicKeyP256 pk -> P256.formatPublicKey pk mformatPublicKey :: PublicKey -> MText-mformatPublicKey = mkMTextUnsafe . formatPublicKey+mformatPublicKey = unsafeMkMText . formatPublicKey instance Buildable PublicKey where build = build . formatPublicKey@@ -340,7 +344,7 @@ SignatureGeneric sig -> formatImpl genericSignatureTag sig mformatSignature :: Signature -> MText-mformatSignature = mkMTextUnsafe . formatSignature+mformatSignature = unsafeMkMText . formatSignature instance Buildable Signature where build = build . formatSignature@@ -433,7 +437,7 @@ = KeyHashEd25519 | KeyHashSecp256k1 | KeyHashP256- deriving stock (Show, Eq, Ord, Bounded, Enum, Generic)+ deriving stock (Show, Eq, Ord, Bounded, Enum, Generic, Lift) instance NFData KeyHashTag @@ -443,7 +447,7 @@ -- ^ We store which curve was used because it affects formatting. , khBytes :: ByteString -- ^ Hash itself.- } deriving stock (Show, Eq, Ord, Generic)+ } deriving stock (Show, Eq, Ord, Generic, Lift) instance NFData KeyHash @@ -467,7 +471,7 @@ formatKeyHash (KeyHash tag bytes) = formatImpl (keyHashTagBytes tag) bytes mformatKeyHash :: KeyHash -> MText-mformatKeyHash = mkMTextUnsafe . formatKeyHash+mformatKeyHash = unsafeMkMText . formatKeyHash instance Buildable KeyHash where build = build . formatKeyHash@@ -485,8 +489,8 @@ in firstRight $ map parse $ minBound :| [succ minBound ..] -parseKeyHashUnsafe :: HasCallStack => Text -> KeyHash-parseKeyHashUnsafe = either (error . pretty) id . parseKeyHash+unsafeParseKeyHash :: HasCallStack => Text -> KeyHash+unsafeParseKeyHash = either (error . pretty) id . parseKeyHash parseKeyHashRaw :: ByteString -> Either CryptoParseError KeyHash parseKeyHashRaw ba =
src/Tezos/Crypto/BLS12381.hs view
@@ -13,13 +13,13 @@ , Bls12381G1 , Bls12381G2 , CurveObject (..)- , fromMichelsonBytesUnsafe+ , unsafeFromMichelsonBytes , MultiplyPoint (..) , DeserializationError (..) , checkPairing -- * Playground- , readFromHexUnsafe+ , unsafeReadFromHex , generateFrom , g1One , g2One@@ -38,13 +38,16 @@ import qualified Data.Curve.Weierstrass.BLS12381 as CW.BLS import qualified Data.Field.Galois as GF import qualified Data.Pairing.BLS12381 as BLS-import Fmt (Buildable(..), pretty, (+|), (|+))+import Fmt (Buildable(..), pretty) import Named (arg, type (:!), (!)) import Text.Hex (decodeHex, encodeHex)+import Text.PrettyPrint.Leijen.Text ((<+>), int, integer) import Util.Instances () import Util.Named () import Util.Num +import Michelson.Printer.Util (RenderDoc (..), renderAnyBuildable, buildRenderDoc)+ -- | Methods common for all BLS12-381 primitives. class CurveObject a where -- | Representation of @0@, aka additive identity.@@ -73,16 +76,16 @@ generateFrom = evalRand generate . mkStdGen -- | Read a value from Michelson's bytes form assuming that it is correct.-fromMichelsonBytesUnsafe :: (CurveObject a, HasCallStack) => ByteString -> a-fromMichelsonBytesUnsafe = either (error . pretty) id . fromMichelsonBytes+unsafeFromMichelsonBytes :: (CurveObject a, HasCallStack) => ByteString -> a+unsafeFromMichelsonBytes = either (error . pretty) id . fromMichelsonBytes -- | Reads an object from hex string. -- -- To be used only in playground and tests.-readFromHexUnsafe :: (CurveObject a, HasCallStack) => String -> a-readFromHexUnsafe hex =+unsafeReadFromHex :: (CurveObject a, HasCallStack) => String -> a+unsafeReadFromHex hex = let bs = decodeHex (toText hex) ?: error "bad hex"- in fromMichelsonBytesUnsafe bs+ in unsafeFromMichelsonBytes bs -- | Multiplication operations on BLS12-381 objects. class MultiplyPoint scalar point where@@ -188,19 +191,22 @@ deriving anyclass (NFData) instance Buildable DeserializationError where- build = \case+ build = buildRenderDoc++instance RenderDoc DeserializationError where+ renderDoc _ = \case CompressedFormIsNotSupported -> "Compressed form of BLS12-381 point is not supported by Tezos" UnexpectedLength (arg #expected -> expected) (arg #given -> given) -> "Unexpected length of BLS12-381 primitive: \- \expected " +| expected |+ ", but given " +| given |+ ""+ \expected" <+> (int expected) <> ", but given" <+> (int given) TooLargeLength (arg #limit -> limit) (arg #given -> given) -> "Too large length of BLS12-381 primitive: \- \limit is " +| limit |+ ", but given " +| given |+ ""+ \limit is" <+> (int limit) <+> ", but given" <+> (int given) ValueOutsideOfField v ->- "Value is too large for the given field of values: " +| v |+ ""+ "Value is too large for the given field of values:" <+> (integer v) PointNotOnCurve bs ->- "Point is not on curve: 0x" +| encodeHex bs |+ ""+ "Point is not on curve: 0x" <> (renderAnyBuildable $ encodeHex bs) {- Note on serialization:
src/Tezos/Crypto/Ed25519.hs view
@@ -135,7 +135,7 @@ formatPublicKey = formatImpl publicKeyTag . unPublicKey mformatPublicKey :: PublicKey -> MText-mformatPublicKey = mkMTextUnsafe . formatPublicKey+mformatPublicKey = unsafeMkMText . formatPublicKey instance Buildable PublicKey where build = build . formatPublicKey@@ -156,7 +156,7 @@ formatSignature = formatImpl signatureTag . unSignature mformatSignature :: Signature -> MText-mformatSignature = mkMTextUnsafe . formatSignature+mformatSignature = unsafeMkMText . formatSignature instance Buildable Signature where build = build . formatSignature
src/Tezos/Crypto/P256.hs view
@@ -157,7 +157,7 @@ formatPublicKey = formatImpl @ByteString publicKeyTag . publicKeyToBytes mformatPublicKey :: PublicKey -> MText-mformatPublicKey = mkMTextUnsafe . formatPublicKey+mformatPublicKey = unsafeMkMText . formatPublicKey instance Buildable PublicKey where build = build . formatPublicKey@@ -169,7 +169,7 @@ formatSignature = formatImpl @ByteString signatureTag . signatureToBytes mformatSignature :: Signature -> MText-mformatSignature = mkMTextUnsafe . formatSignature+mformatSignature = unsafeMkMText . formatSignature instance Buildable Signature where build = build . formatSignature
src/Tezos/Crypto/Secp256k1.hs view
@@ -157,7 +157,7 @@ formatPublicKey = formatImpl @ByteString publicKeyTag . publicKeyToBytes mformatPublicKey :: PublicKey -> MText-mformatPublicKey = mkMTextUnsafe . formatPublicKey+mformatPublicKey = unsafeMkMText . formatPublicKey instance Buildable PublicKey where build = build . formatPublicKey@@ -169,7 +169,7 @@ formatSignature = formatImpl @ByteString signatureTag . signatureToBytes mformatSignature :: Signature -> MText-mformatSignature = mkMTextUnsafe . formatSignature+mformatSignature = unsafeMkMText . formatSignature instance Buildable Signature where build = build . formatSignature
src/Tezos/Crypto/Util.hs view
@@ -40,11 +40,14 @@ import qualified Data.ByteString as BS import qualified Data.ByteString.Base58 as Base58 import qualified Data.ByteString.Lazy as LBS-import Fmt (Buildable, Builder, build, fmt, hexF, (+|), (|+))+import Fmt (Buildable, Builder, build, hexF)+import Text.PrettyPrint.Leijen.Text ((<+>), int, textStrict) import Tezos.Crypto.Hash import Util.Binary (getRemainingByteStringCopy)+import Michelson.Printer.Util (RenderDoc(..), renderAnyBuildable, buildRenderDocExtended) + -- | Error that can happen during parsing of cryptographic primitive types. data CryptoParseError = CryptoParseWrongBase58Check@@ -58,17 +61,21 @@ rnf = rnf @String . show instance Buildable CryptoParseError where- build =- \case- CryptoParseWrongBase58Check -> "Wrong base58check encoding of bytes"- CryptoParseWrongTag tag -> "Prefix is wrong tag: " <> fmt (hexF tag)- CryptoParseCryptoError err ->- "Cryptographic library reported an error: " <>- build (displayException err)- CryptoParseUnexpectedLength what l ->- "Unexpected length of " <> what <> ": " <> build l- CryptoParseBinaryError err -> "" +| err |+ ""+ build = buildRenderDocExtended +instance RenderDoc CryptoParseError where+ renderDoc _ = \case+ CryptoParseWrongBase58Check -> "Wrong base58check encoding of bytes"+ CryptoParseWrongTag tag -> "Prefix is wrong tag:" <+> (renderAnyBuildable $ hexF tag)+ CryptoParseCryptoError err ->+ "Cryptographic library reported an error: " <>+ (renderAnyBuildable $ (displayException err))+ CryptoParseUnexpectedLength what l ->+ "Unexpected length of" <+> renderAnyBuildable what <> ":" <+> int l+ CryptoParseBinaryError err -> textStrict err+++ -- | Encode a bytestring in Base58Check format. encodeBase58Check :: ByteString -> Text encodeBase58Check =@@ -79,8 +86,8 @@ -- | Decode a bytestring from Base58Check format. decodeBase58Check :: Text -> Maybe ByteString-decodeBase58Check text = do- bytes <- Base58.decodeBase58 Base58.bitcoinAlphabet (encodeUtf8 text)+decodeBase58Check base58text = do+ bytes <- Base58.decodeBase58 Base58.bitcoinAlphabet (encodeUtf8 base58text) let (payload, chk) = BS.splitAt (length bytes - 4) bytes guard $ chk == checkSum payload return payload@@ -98,8 +105,8 @@ -- resulting payload is returned. decodeBase58CheckWithPrefix :: ByteString -> Text -> Either B58CheckWithPrefixError ByteString-decodeBase58CheckWithPrefix prefix text =- case decodeBase58Check text of+decodeBase58CheckWithPrefix prefix base58text =+ case decodeBase58Check base58text of Nothing -> Left B58CheckWithPrefixWrongEncoding Just bs -> let (actualPrefix, payload) = BS.splitAt (length prefix) bs@@ -117,12 +124,12 @@ -> (ByteString -> Either CryptoParseError res) -> Text -> Either CryptoParseError res-parseImpl expectedTag constructor text = do+parseImpl expectedTag constructor textToParse = do let convertErr :: B58CheckWithPrefixError -> CryptoParseError convertErr = \case B58CheckWithPrefixWrongPrefix prefix -> CryptoParseWrongTag prefix B58CheckWithPrefixWrongEncoding -> CryptoParseWrongBase58Check- payload <- first convertErr $ decodeBase58CheckWithPrefix expectedTag text+ payload <- first convertErr $ decodeBase58CheckWithPrefix expectedTag textToParse constructor payload -- | Returns first encountered 'Right' in a list. If there are none,
src/Util/CLI.hs view
@@ -20,11 +20,13 @@ , mkCLOptionParserExt , mkCLArgumentParser , mkCLArgumentParserExt+ , mkCommandParser , namedParser -- ** Helpers for defining 'HasCLReader' , eitherReader , readerError+ , integralReader ) where import Data.Text.Manipulate (toSpinal)@@ -37,6 +39,7 @@ import Util.Instances () import Util.Named+import Util.Num -- | Maybe add the default value and make sure it will be shown in -- help message.@@ -76,27 +79,54 @@ -- else, but it still sounds a bit dangerous. instance HasCLReader Natural where- getReader = Opt.auto+ getReader = integralReader getMetavar = "NATURAL NUMBER" instance HasCLReader Word64 where- getReader = Opt.auto+ getReader = integralReader -- ↓ Same as for 'Natural', the user usually does not care whether -- the number is bounded (reasonable values should fit anyway).+ -- We will apply the same rule for other numeric instances. getMetavar = "NATURAL NUMBER" +instance HasCLReader Word32 where+ getReader = integralReader+ getMetavar = "NATURAL NUMBER"+ instance HasCLReader Word16 where- getReader = Opt.auto- -- ↓ Same as for 'Natural', the user usually does not care whether- -- the number is bounded (reasonable values should fit anyway).+ getReader = integralReader getMetavar = "NATURAL NUMBER" +instance HasCLReader Word8 where+ getReader = integralReader+ getMetavar = "NATURAL NUMBER"++instance HasCLReader Word where+ getReader = integralReader+ getMetavar = "NATURAL NUMBER"+ instance HasCLReader Integer where- getReader = Opt.auto+ getReader = integralReader getMetavar = "INTEGER" +instance HasCLReader Int64 where+ getReader = integralReader+ getMetavar = "INTEGER"++instance HasCLReader Int32 where+ getReader = integralReader+ getMetavar = "INTEGER"++instance HasCLReader Int16 where+ getReader = integralReader+ getMetavar = "INTEGER"++instance HasCLReader Int8 where+ getReader = integralReader+ getMetavar = "INTEGER"+ instance HasCLReader Int where- getReader = Opt.auto+ getReader = integralReader getMetavar = "INTEGER" instance HasCLReader Text where@@ -107,6 +137,15 @@ getReader = Opt.str getMetavar = "STRING" +-- | Parse a number, checking for overflows and other stuff.+integralReader :: Integral a => Opt.ReadM a+integralReader = do+ int <- Opt.auto @Integer+ fromIntegralChecked int+ & either (readerError . addPrefix . toString) pure+ where+ addPrefix = ("failed to parse command-line numeric argument: " <>)+ -- | Create a 'Opt.Parser' for a value using 'HasCLReader' instance -- (hence @CL@ in the name). It uses reader and metavar from that -- class, the rest should be supplied as arguments.@@ -160,6 +199,13 @@ help hInfo : maybeAddDefault pretty defValue : mods++-- | Parser for command options+mkCommandParser :: String -> Opt.Parser a -> String -> Opt.Mod Opt.CommandFields a+mkCommandParser commandName parser desc =+ Opt.command commandName $+ Opt.info (Opt.helper <*> parser) $+ Opt.progDesc desc -- | Create a 'Opt.Parser' for a value using its type-level name. --
src/Util/Peano.hs view
@@ -25,12 +25,10 @@ , Nat (Z, S) , ToPeano , FromPeano- , KnownPeano (..) , SingNat (SZ, SS)+ , Decrement , type (>)- , peanoVal'- , peanoValSing , peanoSing -- * Peano Arithmetic@@ -89,21 +87,6 @@ FromPeano 'Z = 0 FromPeano ('S a) = 1 + FromPeano a -class KnownPeano (n :: Peano) where- peanoVal :: proxy n -> Natural--instance KnownPeano 'Z where- peanoVal _ = 0-instance KnownPeano a => KnownPeano ('S a) where- peanoVal _ = peanoVal' @a + 1--peanoVal' :: forall n. KnownPeano n => Natural-peanoVal' = peanoVal (Proxy @n)---- | Get runtime value from singleton.-peanoValSing :: forall n. KnownPeano n => Sing n -> Natural-peanoValSing _ = peanoVal' @n- -- | Get the peano singleton for a given type-level nat literal. -- -- >>> peanoSing @2@@ -111,12 +94,9 @@ peanoSing :: forall (n :: GHC.Nat). SingI (ToPeano n) => SingNat (ToPeano n) peanoSing = sing @(ToPeano n) -instance KnownPeano a => MockableConstraint (KnownPeano a) where- provideConstraintUnsafe = Dict- data SingNat (n :: Nat) where SZ :: SingNat 'Z- SS :: (SingI n, KnownPeano n) => SingNat n -> SingNat ('S n)+ SS :: !(SingNat n) -> SingNat ('S n) deriving stock instance Show (SingNat (n :: Nat)) deriving stock instance Eq (SingNat (n :: Nat))@@ -128,7 +108,7 @@ instance SingI 'Z where sing = SZ-instance (SingI n, KnownPeano n) => SingI ('S n) where+instance SingI n => SingI ('S n) where sing = SS (sing @n) ----------------------------------------------------------------------------@@ -288,10 +268,10 @@ RequireLongerOrSameLength l a instance MockableConstraint (RequireLongerOrSameLength l a) where- provideConstraintUnsafe = unsafeCoerce $ Dict @(RequireLongerOrSameLength '[] 'Z)+ unsafeProvideConstraint = unsafeCoerce $ Dict @(RequireLongerOrSameLength '[] 'Z) instance MockableConstraint (RequireLongerThan l a) where- provideConstraintUnsafe = unsafeCoerce $ Dict @(RequireLongerThan '[()] 'Z)+ unsafeProvideConstraint = unsafeCoerce $ Dict @(RequireLongerThan '[()] 'Z) ---------------------------------------------------------------------------- -- Length constraints 'Dict'ionaries
+ src/Util/PeanoNatural.hs view
@@ -0,0 +1,84 @@+-- SPDX-FileCopyrightText: 2021 Tocqueville Group+--+-- SPDX-License-Identifier: LicenseRef-MIT-TQ++-- | Utility for 'PeanoNatural'+--+-- At the moment, we have no other libriaries with that would+-- provide effective implementation of type-level natural+-- numbers. So we define our own data type called @PeanoNatural@.+-- Using this type one may extract a term-level natural number+-- from a type-level one quite simply.+module Util.PeanoNatural+ ( PeanoNatural (Zero, Succ, One, Two)+ , toPeanoNatural+ , toPeanoNatural'+ , fromPeanoNatural+ , singPeanoVal+ ) where++import Data.Singletons (SingI (..))+import Util.Peano (Nat (Z, S), SingNat(..), ToPeano)+import qualified GHC.TypeNats as GHC (Nat)++-- | PeanoNatural data type+--+-- The @PN@ constructor stores @s :: SingNat n@ and @k :: Natural@+-- with the following invariant:+-- if @PN s k :: PeanoNatural n@, then @k == n@.+-- This definition allows extracting values of Natural+-- without O(n) conversion from @SingNat n@.+data PeanoNatural (n :: Nat) = PN !(SingNat n) !Natural++deriving stock instance Show (PeanoNatural n)+deriving stock instance Eq (PeanoNatural n)++instance NFData (PeanoNatural n) where+ rnf (PN s _) = rnf s++data MatchPS n where+ PS_Match :: PeanoNatural n -> MatchPS ('S n)+ PS_Mismatch :: MatchPS n++matchPS :: PeanoNatural n -> MatchPS n+matchPS (PN (SS m) k) = PS_Match (PN m (k - 1))+matchPS _ = PS_Mismatch++-- | Patterns 'Zero' and 'Succ'+-- We introduce pattern synonyms 'Zero' and 'Succ' assuming that+-- 'Zero' and 'Succ' cover all possible cases that satisfy the invariant.+-- Using these patterns, we also avoid cases when `k /= peanoValSing @n s`+pattern Zero :: () => (n ~ 'Z) => PeanoNatural n+pattern Zero = PN SZ 0++pattern Succ :: () => (n ~ 'S m) => PeanoNatural m -> PeanoNatural n+pattern Succ s <- (matchPS -> PS_Match s) where+ Succ (PN n k) = PN (SS n) (k+1)+{-# COMPLETE Zero, Succ #-}++-- | The following patterns are introduced for convenience.+-- This allow us to avoid writing @Succ (Succ Zero)@ in+-- several places.+pattern One :: () => (n ~ ('S 'Z)) => PeanoNatural n+pattern One = Succ Zero++pattern Two :: () => (n ~ ('S ('S 'Z))) => PeanoNatural n+pattern Two = Succ One++fromPeanoNatural :: forall n. PeanoNatural n -> Natural+fromPeanoNatural (PN _ n) = n++-- | toPeanoNatural and toPeanoNatural' connect PeanoNatural with+-- natural numbers known at run-time.+singPeanoVal :: forall (n :: Nat). SingNat n -> Natural+singPeanoVal = \case+ SZ -> 0+ SS a -> 1 + singPeanoVal a++toPeanoNatural :: forall n. SingI n => PeanoNatural n+toPeanoNatural = let pSing = sing @n in+ PN pSing $ singPeanoVal pSing++toPeanoNatural'+ :: forall (n :: GHC.Nat). SingI (ToPeano n) => PeanoNatural (ToPeano n)+toPeanoNatural' = toPeanoNatural @(ToPeano n)
src/Util/Positive.hs view
@@ -20,7 +20,7 @@ -- -- We define our own datatype in order to have 'Data' instance for it, -- which can not be derived for third-party types without exported constructor.-newtype Positive = PositiveUnsafe { unPositive :: Natural }+newtype Positive = UnsafePositive { unPositive :: Natural } deriving stock (Eq, Ord, Data, Generic) deriving newtype (Show, Buildable, ToJSON, FromJSON) @@ -28,13 +28,13 @@ mkPositive :: (Integral i, Buildable i) => i -> Either Text Positive mkPositive a- | a > 0 = Right $ PositiveUnsafe (fromIntegral a)+ | a > 0 = Right $ UnsafePositive (fromIntegral a) | otherwise = Left $ "Number is not positive: " <> pretty a -- | Count length of non-empty list. lengthNE :: NonEmpty a -> Positive-lengthNE = PositiveUnsafe . fromIntegral . length+lengthNE = UnsafePositive . fromIntegral . length -- | Produce a non empty list consisting of the given value. replicateNE :: Positive -> a -> NonEmpty a-replicateNE (PositiveUnsafe i) a = a :| replicate (fromIntegral i - 1) a+replicateNE (UnsafePositive i) a = a :| replicate (fromIntegral i - 1) a
+ src/Util/Sing.hs view
@@ -0,0 +1,93 @@+-- SPDX-FileCopyrightText: 2021 Tocqueville Group+--+-- SPDX-License-Identifier: LicenseRef-MIT-TQ++module Util.Sing+ ( eqI+ , eqParamSing+ , eqParamSing2+ , eqParamSing3+ , castSing+ , SingI1(..)+ ) where++import Data.Type.Equality ((:~:)(..), TestEquality(..))+import Data.Typeable (eqT)+import Data.Singletons (KindOf, Sing, SingI, sing)+import Data.Singletons.Decide (SDecide, decideEquality)++-- | Version of 'testEquality' that uses 'SingI'+eqI :: forall a b. (SingI a, SingI b, TestEquality (Sing @(KindOf a))) => Maybe (a :~: b)+eqI = testEquality (sing @a) (sing @b)++-- | Suppose you have a data type `X` with parameter `a` and you have+-- two values: `x1 :: X a1` and `x2 :: X a2`. You can't compare them+-- using '==', because they have different types. However, you can+-- compare them using 'eqParamSing' as long as both parameters have+-- SingI instances and their kind is `SDecide`.+eqParamSing ::+ forall a1 a2 t.+ ( SingI a1+ , SingI a2+ , SDecide (KindOf a1)+ , Eq (t a1)+ )+ => t a1+ -> t a2+ -> Bool+eqParamSing t1 t2 = isJust @() $ do+ Refl <- sing @a1 `decideEquality` sing @a2+ guard (t1 == t2)++-- | Version of 'eqParamSing' for types with 2 parameters.+eqParamSing2 ::+ forall a1 a2 b1 b2 t.+ ( SingI a1+ , SingI a2+ , SingI b1+ , SingI b2+ , SDecide (KindOf a1)+ , SDecide (KindOf b1)+ , Eq (t a1 b2)+ )+ => t a1 b1+ -> t a2 b2+ -> Bool+eqParamSing2 t1 t2 = isJust @() $ do+ Refl <- sing @a1 `decideEquality` sing @a2+ Refl <- sing @b1 `decideEquality` sing @b2+ guard (t1 == t2)++-- | Version of 'eqParamSing' for types with 3 parameters.+eqParamSing3 ::+ forall instr1 instr2 a1 a2 b1 b2 t.+ ( Typeable instr1+ , Typeable instr2+ , SingI a1+ , SingI a2+ , SingI b1+ , SingI b2+ , SDecide (KindOf a1)+ , SDecide (KindOf b1)+ , Eq (t instr1 a1 b1)+ )+ => t instr1 a1 b1+ -> t instr2 a2 b2+ -> Bool+eqParamSing3 t1 t2 = isJust @() $ do+ Refl <- eqT @instr1 @instr2+ Refl <- sing @a1 `decideEquality` sing @a2+ Refl <- sing @b1 `decideEquality` sing @b2+ guard (t1 == t2)++castSing :: forall a b t.+ (SingI a, SingI b, SDecide (KindOf a))+ => t a+ -> Maybe (t b)+castSing ca = do+ Refl <- sing @a `decideEquality` sing @b+ return ca++-- Second-order analogue of 'SingI'+class SingI1 f where+ withSingI1 :: forall x r. SingI x => (SingI (f x) => r) -> r
src/Util/Type.hs view
@@ -40,8 +40,8 @@ , onFirst ) where -import Data.Constraint ((:-)(..), Dict(..), (\\))-import Data.Type.Bool (type (&&), If, Not)+import Data.Constraint (Dict(..), (:-)(..), (\\))+import Data.Type.Bool (If, Not, type (&&)) import Data.Type.Equality (type (==)) import Data.Vinyl.Core (Rec(..)) import qualified Data.Vinyl.Functor as Vinyl@@ -80,10 +80,10 @@ -- | A natural conclusion from the fact that an error has not occurred. failUnlessEvi :: forall cond msg. FailUnless cond msg :- (cond ~ 'True)-failUnlessEvi = Sub provideConstraintUnsafe+failUnlessEvi = Sub unsafeProvideConstraint failWhenEvi :: forall cond msg. FailWhen cond msg :- (cond ~ 'False)-failWhenEvi = Sub provideConstraintUnsafe+failWhenEvi = Sub unsafeProvideConstraint type family AllUnique (l :: [k]) :: Bool where AllUnique '[] = 'True@@ -126,7 +126,7 @@ -- | Reify type equality from boolean equality. reifyTypeEquality :: forall a b x. (a == b) ~ 'True => (a ~ b => x) -> x-reifyTypeEquality x = x \\ provideConstraintUnsafe @(a ~ b)+reifyTypeEquality x = x \\ unsafeProvideConstraint @(a ~ b) -- | Similar to @SingI []@, but does not require individual elements to be also -- instance of @SingI@.@@ -172,7 +172,7 @@ -- especially if you have complex types. -- But (++) type family is associative, so let's define this small hack. listOfTypesConcatAssociativityAxiom :: forall a b c . Dict (ConcatListOfTypesAssociativity a b c)-listOfTypesConcatAssociativityAxiom = provideConstraintUnsafe+listOfTypesConcatAssociativityAxiom = unsafeProvideConstraint -- | Constaints that can be provided on demand. --@@ -182,45 +182,45 @@ -- proof would be too difficult. class MockableConstraint (c :: Constraint) where -- | Produce a constraint out of thin air.- provideConstraintUnsafe :: Dict c+ unsafeProvideConstraint :: Dict c instance MockableConstraint (a ~ b) where- provideConstraintUnsafe = unsafeCoerce $ Dict @(Int ~ Int)+ unsafeProvideConstraint = unsafeCoerce $ Dict @(Int ~ Int) -- | In majority of the cases we don't want to mock typeclass constraints -- since coercing instances of typeclasses with methods is utterly unsafe. instance {-# OVERLAPPABLE #-} c a => MockableConstraint (c a) where- provideConstraintUnsafe = Dict+ unsafeProvideConstraint = Dict instance ( MockableConstraint c1 , MockableConstraint c2 ) => MockableConstraint (c1, c2) where- provideConstraintUnsafe = runIdentity $ do- Dict <- pure $ provideConstraintUnsafe @c1- Dict <- pure $ provideConstraintUnsafe @c2+ unsafeProvideConstraint = runIdentity $ do+ Dict <- pure $ unsafeProvideConstraint @c1+ Dict <- pure $ unsafeProvideConstraint @c2 return Dict- {-# INLINE provideConstraintUnsafe #-}+ {-# INLINE unsafeProvideConstraint #-} instance ( MockableConstraint c1 , MockableConstraint c2 , MockableConstraint c3 ) => MockableConstraint (c1, c2, c3) where- provideConstraintUnsafe = runIdentity $ do- Dict <- pure $ provideConstraintUnsafe @(c1, c2)- Dict <- pure $ provideConstraintUnsafe @c3+ unsafeProvideConstraint = runIdentity $ do+ Dict <- pure $ unsafeProvideConstraint @(c1, c2)+ Dict <- pure $ unsafeProvideConstraint @c3 return Dict- {-# INLINE provideConstraintUnsafe #-}+ {-# INLINE unsafeProvideConstraint #-} instance ( MockableConstraint c1 , MockableConstraint c2 , MockableConstraint c3 , MockableConstraint c4 ) => MockableConstraint (c1, c2, c3, c4) where- provideConstraintUnsafe = runIdentity $ do- Dict <- pure $ provideConstraintUnsafe @(c1, c2, c3)- Dict <- pure $ provideConstraintUnsafe @c4+ unsafeProvideConstraint = runIdentity $ do+ Dict <- pure $ unsafeProvideConstraint @(c1, c2, c3)+ Dict <- pure $ unsafeProvideConstraint @c4 return Dict- {-# INLINE provideConstraintUnsafe #-}+ {-# INLINE unsafeProvideConstraint #-} instance ( MockableConstraint c1 , MockableConstraint c2@@ -228,11 +228,11 @@ , MockableConstraint c4 , MockableConstraint c5 ) => MockableConstraint (c1, c2, c3, c4, c5) where- provideConstraintUnsafe = runIdentity $ do- Dict <- pure $ provideConstraintUnsafe @(c1, c2, c3, c4)- Dict <- pure $ provideConstraintUnsafe @c5+ unsafeProvideConstraint = runIdentity $ do+ Dict <- pure $ unsafeProvideConstraint @(c1, c2, c3, c4)+ Dict <- pure $ unsafeProvideConstraint @c5 return Dict- {-# INLINE provideConstraintUnsafe #-}+ {-# INLINE unsafeProvideConstraint #-} -- | Utility function to help transform the first argument of a binfunctor. onFirst :: Bifunctor p => p a c -> (a -> b) -> p b c
src/Util/TypeLits.hs view
@@ -17,9 +17,11 @@ , ErrorMessage (..) , TypeErrorUnless+ , AssertTypesEqual ) where import GHC.TypeLits+import Data.Type.Equality symbolValT :: forall s. KnownSymbol s => Proxy s -> Text symbolValT = toText . symbolVal@@ -83,3 +85,18 @@ type family TypeErrorUnlessHelper (cond :: Bool) (err :: ErrorMessage) :: Constraint where TypeErrorUnlessHelper 'True _ = () TypeErrorUnlessHelper 'False err = TypeError err++-- | Condition Error helper to check if two types are equal+--+-- >>> :k! AssertTypesEqual Int Int ('Text "This should not result in a failure")+-- AssertTypesEqual Int Int ('Text "This should not result in a failure") :: Constraint+-- = (() :: Constraint, Int ~ Int)+--+-- >>> :k! AssertTypesEqual Bool Int ('Text "This should result in a failure")+-- AssertTypesEqual Bool Int ('Text "This should result in a failure") :: Constraint+-- = ((TypeError ...), Bool ~ Int)+type AssertTypesEqual a b (err :: ErrorMessage) =+ ( TypeErrorUnlessHelper (a == b) err+ -- The reasons for the constraint below are the same as those in @TypeErrorUnless@ constructor+ , a ~ b+ )
src/Util/Typeable.hs view
@@ -6,37 +6,21 @@ -- | Utility for 'Typeable'. module Util.Typeable- ( gcastE- , eqP- , eqParam1+ ( eqParam1 , eqParam2 , eqParam3 , eqExt , compareExt , castIgnoringPhantom , eqTypeIgnoringPhantom- -- * Re-exports , (:~:) (..) , eqT ) where import Data.Coerce (coerce)-import Data.Typeable ((:~:)(..), eqT, gcast, typeRep)-import Fmt ((+||), (||+))+import Data.Typeable (eqT, typeRep, (:~:)(..)) import qualified Type.Reflection as Refl---- | Like 'gcast', casts some container's elements,--- producing informative error on mismatch.-gcastE :: forall a b t. (Typeable a, Typeable b) => t a -> Either Text (t b)-gcastE = maybeToRight errMsg . gcast- where- errMsg = "Type mismatch: expected " +|| typeRep (Proxy @b) ||+- ", got " +|| typeRep (Proxy @a) ||+ ""---- | 'Proxy' version of 'eqT'.-eqP :: (Typeable a, Typeable b) => Proxy a -> Proxy b -> Maybe (a :~: b)-eqP (_ :: Proxy a) (_ :: Proxy b) = eqT @a @b -- | Suppose you have a data type `X` with parameter `a` and you have -- two values: `x1 :: X a1` and `x2 :: X a2`. You can't compare them