Safe Haskell | None |
---|---|
Language | Haskell2010 |
Module, containing restrictions imposed by instruction or value scope.
Michelson have multiple restrictions on values, examples:
* operation
type cannot appear in parameter.
* big_map
type cannot appear in PUSH
-able constants.
* contract
type cannot appear in type we UNPACK
to.
Thus we declare multiple "scopes" - constraints applied in corresponding
situations, for instance
* ParameterScope
;
* StorageScope
;
* ConstantScope
.
Also we separate multiple "classes" of scope-related constraints.
ParameterScope
and similar ones are used within Michelson engine, they are understandable by GHC but produce not very clarifying errors.ProperParameterBetterErrors
and similar ones are middle-layer constraints, they produce human-readable errors but GHC cannot make conclusions from them. They are supposed to be used only by eDSLs to define their own high-level constraints.- Lorentz and other eDSLs may declare their own constraints, in most cases
you should use them. For example see
Constraints
module.
Synopsis
- type ParameterScope t = (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t)
- type StorageScope t = (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t)
- type ConstantScope t = (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t)
- type PackedValScope t = (SingI t, HasNoOp t, HasNoBigMap t)
- type UnpackedValScope t = (PackedValScope t, ConstantScope t)
- type PrintedValScope t = (SingI t, HasNoOp t)
- type ProperParameterBetterErrors t = (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t)
- type ProperStorageBetterErrors t = (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t)
- type ProperConstantBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t)
- type ProperPackedValBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t)
- type ProperUnpackedValBetterErrors t = (ProperPackedValBetterErrors t, ProperConstantBetterErrors t)
- type ProperPrintedValBetterErrors t = (SingI t, ForbidOp t)
- properParameterEvi :: forall t. ProperParameterBetterErrors t :- ParameterScope t
- properStorageEvi :: forall t. ProperStorageBetterErrors t :- StorageScope t
- properConstantEvi :: forall t. ProperConstantBetterErrors t :- ConstantScope t
- properPackedValEvi :: forall t. ProperPackedValBetterErrors t :- PackedValScope t
- properUnpackedValEvi :: forall t. ProperUnpackedValBetterErrors t :- UnpackedValScope t
- properPrintedValEvi :: forall t. ProperPrintedValBetterErrors t :- PrintedValScope t
- newtype a :- b = Sub (a -> Dict b)
- class ContainsBigMap t ~ False => HasNoBigMap t
- class ContainsNestedBigMaps t ~ False => HasNoNestedBigMaps t
- class ContainsOp t ~ False => HasNoOp t
- class ContainsContract t ~ False => HasNoContract t
- type family ContainsBigMap (t :: T) :: Bool where ...
- type family ContainsNestedBigMaps (t :: T) :: Bool where ...
- type ForbidOp t = FailOnOperationFound (ContainsOp t)
- type ForbidContract t = FailOnContractFound (ContainsContract t)
- type ForbidBigMap t = FailOnBigMapFound (ContainsBigMap t)
- type ForbidNestedBigMaps t = FailOnNestedBigMapsFound (ContainsNestedBigMaps t)
- type family FailOnBigMapFound (enabled :: Bool) :: Constraint where ...
- type family FailOnNestedBigMapsFound (enabled :: Bool) :: Constraint where ...
- type family FailOnOperationFound (enabled :: Bool) :: Constraint where ...
- data OpPresence (t :: T)
- data ContractPresence (t :: T)
- = ContainsContract t ~ True => ContractPresent
- | ContainsContract t ~ False => ContractAbsent
- data BigMapPresence (t :: T)
- = ContainsBigMap t ~ True => BigMapPresent
- | ContainsBigMap t ~ False => BigMapAbsent
- data NestedBigMapsPresence (t :: T)
- checkOpPresence :: Sing (ty :: T) -> OpPresence ty
- checkContractTypePresence :: Sing (ty :: T) -> ContractPresence ty
- checkBigMapPresence :: Sing (ty :: T) -> BigMapPresence ty
- checkNestedBigMapsPresence :: Sing (ty :: T) -> NestedBigMapsPresence ty
- opAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoOp t)
- contractTypeAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoContract t)
- bigMapAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoBigMap t)
- nestedBigMapsAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoNestedBigMaps t)
- forbiddenOp :: forall t a. (SingI t, ForbidOp t) => (HasNoOp t => a) -> a
- forbiddenContractType :: forall t a. (SingI t, ForbidContract t) => (HasNoContract t => a) -> a
- forbiddenBigMap :: forall t a. (SingI t, ForbidBigMap t) => (HasNoBigMap t => a) -> a
- forbiddenNestedBigMaps :: forall t a. (SingI t, ForbidNestedBigMaps t) => (HasNoNestedBigMaps t => a) -> a
- withDict :: HasDict c e => e -> (c -> r) -> r
Scopes
type ParameterScope t = (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t) Source #
Alias for constraints which Michelson applies to parameter.
type StorageScope t = (Typeable t, SingI t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t) Source #
Alias for constraints which Michelson applies to contract storage.
type ConstantScope t = (SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t) Source #
Alias for constraints which Michelson applies to pushed constants.
type PackedValScope t = (SingI t, HasNoOp t, HasNoBigMap t) Source #
Alias for constraints which Michelson applies to packed values.
type UnpackedValScope t = (PackedValScope t, ConstantScope t) Source #
Alias for constraints which Michelson applies to unpacked values.
It is different from PackedValScope
, e.g. contract
type cannot appear
in a value we unpack to.
type PrintedValScope t = (SingI t, HasNoOp t) Source #
Alias for constraints which are required for printing.
type ProperParameterBetterErrors t = (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t) Source #
type ProperStorageBetterErrors t = (Typeable t, SingI t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t) Source #
type ProperConstantBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t) Source #
type ProperPackedValBetterErrors t = (SingI t, ForbidOp t, ForbidBigMap t) Source #
type ProperUnpackedValBetterErrors t = (ProperPackedValBetterErrors t, ProperConstantBetterErrors t) Source #
type ProperPrintedValBetterErrors t = (SingI t, ForbidOp t) Source #
properParameterEvi :: forall t. ProperParameterBetterErrors t :- ParameterScope t Source #
properStorageEvi :: forall t. ProperStorageBetterErrors t :- StorageScope t Source #
properConstantEvi :: forall t. ProperConstantBetterErrors t :- ConstantScope t Source #
properPackedValEvi :: forall t. ProperPackedValBetterErrors t :- PackedValScope t Source #
properUnpackedValEvi :: forall t. ProperUnpackedValBetterErrors t :- UnpackedValScope t Source #
properPrintedValEvi :: forall t. ProperPrintedValBetterErrors t :- PrintedValScope t Source #
This is the type of entailment.
a
is read as :-
ba
"entails" b
.
With this we can actually build a category for Constraint
resolution.
e.g.
Because
is a superclass of Eq
a
, we can show that Ord
a
entails Ord
a
.Eq
a
Because instance
exists, we can show that Ord
a => Ord
[a]
entails Ord
a
as well.Ord
[a]
This relationship is captured in the :-
entailment type here.
Since p
and entailment composes, :-
p:-
forms the arrows of a
Category
of constraints. However, Category
only became sufficiently
general to support this instance in GHC 7.8, so prior to 7.8 this instance
is unavailable.
But due to the coherence of instance resolution in Haskell, this Category
has some very interesting properties. Notably, in the absence of
IncoherentInstances
, this category is "thin", which is to say that
between any two objects (constraints) there is at most one distinguishable
arrow.
This means that for instance, even though there are two ways to derive
, the answers from these two paths _must_ by
construction be equal. This is a property that Haskell offers that is
pretty much unique in the space of languages with things they call "type
classes".Ord
a :-
Eq
[a]
What are the two ways?
Well, we can go from
via the
superclass relationship, and then from Ord
a :-
Eq
a
via the
instance, or we can go from Eq
a :-
Eq
[a]
via the instance
then from Ord
a :-
Ord
[a]
through the superclass relationship
and this diagram by definition must "commute".Ord
[a] :-
Eq
[a]
Diagrammatically,
Ord a ins / \ cls v v Ord [a] Eq a cls \ / ins v v Eq [a]
This safety net ensures that pretty much anything you can write with this library is sensible and can't break any assumptions on the behalf of library authors.
Instances
Category (:-) | Possible since GHC 7.8, when |
() :=> (Eq (a :- b)) | |
() :=> (Ord (a :- b)) | |
() :=> (Show (a :- b)) | |
a => HasDict b (a :- b) | |
Defined in Data.Constraint | |
Eq (a :- b) | Assumes |
(Typeable p, Typeable q, p, q) => Data (p :- q) | |
Defined in Data.Constraint gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> (p :- q) -> c (p :- q) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (p :- q) # toConstr :: (p :- q) -> Constr # dataTypeOf :: (p :- q) -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (p :- q)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (p :- q)) # gmapT :: (forall b. Data b => b -> b) -> (p :- q) -> p :- q # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> (p :- q) -> r # gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> (p :- q) -> r # gmapQ :: (forall d. Data d => d -> u) -> (p :- q) -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> (p :- q) -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> (p :- q) -> m (p :- q) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> (p :- q) -> m (p :- q) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> (p :- q) -> m (p :- q) # | |
Ord (a :- b) | Assumes |
Defined in Data.Constraint | |
Show (a :- b) | |
a => NFData (a :- b) | |
Defined in Data.Constraint |
Implementation internals
class ContainsBigMap t ~ False => HasNoBigMap t Source #
Constraint which ensures that bigmap does not appear in a given type.
Instances
ContainsBigMap t ~ False => HasNoBigMap t Source # | |
Defined in Michelson.Typed.Scope |
class ContainsNestedBigMaps t ~ False => HasNoNestedBigMaps t Source #
Constraint which ensures that there are no nested bigmaps
Instances
ContainsNestedBigMaps t ~ False => HasNoNestedBigMaps t Source # | |
Defined in Michelson.Typed.Scope |
class ContainsOp t ~ False => HasNoOp t Source #
Constraint which ensures that operation type does not appear in a given type.
Not just a type alias in order to be able to partially apply it
(e.g. in Each
).
Instances
ContainsOp t ~ False => HasNoOp t Source # | |
Defined in Michelson.Typed.Scope |
class ContainsContract t ~ False => HasNoContract t Source #
Constraint which ensures that contract type does not appear in a given type.
Instances
ContainsContract t ~ False => HasNoContract t Source # | |
Defined in Michelson.Typed.Scope |
type family ContainsBigMap (t :: T) :: Bool where ... Source #
Whether this type contains TBigMap
type.
ContainsBigMap (Tc _) = False | |
ContainsBigMap TKey = False | |
ContainsBigMap TUnit = False | |
ContainsBigMap TSignature = False | |
ContainsBigMap TChainId = False | |
ContainsBigMap (TOption t) = ContainsBigMap t | |
ContainsBigMap (TList t) = ContainsBigMap t | |
ContainsBigMap (TSet _) = False | |
ContainsBigMap TOperation = False | |
ContainsBigMap (TContract t) = ContainsBigMap t | |
ContainsBigMap (TPair a b) = ContainsBigMap a || ContainsBigMap b | |
ContainsBigMap (TOr a b) = ContainsBigMap a || ContainsBigMap b | |
ContainsBigMap (TLambda _ _) = False | |
ContainsBigMap (TMap _ v) = ContainsBigMap v | |
ContainsBigMap (TBigMap _ _) = True |
type family ContainsNestedBigMaps (t :: T) :: Bool where ... Source #
Whether this type contains a type with nested TBigMap
s .
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.
type ForbidOp t = FailOnOperationFound (ContainsOp t) Source #
This is like HasNoOp
, it raises a more human-readable error
when t
type is concrete, but GHC cannot make any conclusions
from such constraint as it can for 'HasNoOp.
Use it in our eDSL.
type ForbidContract t = FailOnContractFound (ContainsContract t) Source #
type ForbidBigMap t = FailOnBigMapFound (ContainsBigMap t) Source #
type family FailOnBigMapFound (enabled :: Bool) :: Constraint where ... Source #
Report a human-readable error about TBigMap
at a wrong place.
FailOnBigMapFound True = TypeError (Text "BigMaps are not allowed in this scope") | |
FailOnBigMapFound False = () |
type family FailOnNestedBigMapsFound (enabled :: Bool) :: Constraint where ... Source #
FailOnNestedBigMapsFound True = TypeError (Text "Nested BigMaps are not allowed") | |
FailOnNestedBigMapsFound False = () |
type family FailOnOperationFound (enabled :: Bool) :: Constraint where ... Source #
Report a human-readable error about TOperation
at a wrong place.
FailOnOperationFound True = TypeError (Text "Operations are not allowed in this scope") | |
FailOnOperationFound False = () |
data OpPresence (t :: T) Source #
Whether the type contains TOperation
, with proof.
data ContractPresence (t :: T) Source #
ContainsContract t ~ True => ContractPresent | |
ContainsContract t ~ False => ContractAbsent |
data BigMapPresence (t :: T) Source #
ContainsBigMap t ~ True => BigMapPresent | |
ContainsBigMap t ~ False => BigMapAbsent |
data NestedBigMapsPresence (t :: T) Source #
checkOpPresence :: Sing (ty :: T) -> OpPresence ty Source #
Check at runtime whether the given type contains TOperation
.
checkContractTypePresence :: Sing (ty :: T) -> ContractPresence ty Source #
Check at runtime whether the given type contains TContract
.
checkBigMapPresence :: Sing (ty :: T) -> BigMapPresence ty Source #
Check at runtime whether the given type contains TBigMap
.
checkNestedBigMapsPresence :: Sing (ty :: T) -> NestedBigMapsPresence ty Source #
Check at runtime whether the given type contains TBigMap
.
opAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoOp t) Source #
Check at runtime that the given type does not contain TOperation
.
contractTypeAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoContract t) Source #
Check at runtime that the given type does not contain TContract
.
bigMapAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoBigMap t) Source #
Check at runtime that the given type does not containt TBigMap
nestedBigMapsAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoNestedBigMaps t) Source #
Check at runtime that the given type does not contain nested TBigMap
forbiddenContractType :: forall t a. (SingI t, ForbidContract t) => (HasNoContract t => a) -> a Source #
Reify HasNoContract
contraint from ForbidContract
.
forbiddenBigMap :: forall t a. (SingI t, ForbidBigMap t) => (HasNoBigMap t => a) -> a Source #
forbiddenNestedBigMaps :: forall t a. (SingI t, ForbidNestedBigMaps t) => (HasNoNestedBigMaps t => a) -> a Source #
Re-exports
withDict :: HasDict c e => e -> (c -> r) -> r #
From a Dict
, takes a value in an environment where the instance
witnessed by the Dict
is in scope, and evaluates it.
Essentially a deconstruction of a Dict
into its continuation-style
form.
Can also be used to deconstruct an entailment, a
, using a context :-
ba
.
withDict ::Dict
c -> (c => r) -> r withDict :: a => (a:-
c) -> (c => r) -> r