From ff7a8abb27cdbc4fd4528b7ffd2d791cbefa5324 Mon Sep 17 00:00:00 2001 From: bruno Date: Mon, 5 Feb 2018 15:15:43 +0100 Subject: [PATCH] Michelson: mv registration of type-checking errors in a specific file --- .../lib_protocol/src/TEZOS_PROTOCOL | 1 + .../lib_protocol/src/script_ir_translator.ml | 533 ----------------- .../lib_protocol/src/script_ir_translator.mli | 3 - .../src/script_tc_errors_registration.ml | 549 ++++++++++++++++++ src/proto_alpha/lib_protocol/src/services.ml | 2 +- 5 files changed, 551 insertions(+), 537 deletions(-) create mode 100644 src/proto_alpha/lib_protocol/src/script_tc_errors_registration.ml diff --git a/src/proto_alpha/lib_protocol/src/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/src/TEZOS_PROTOCOL index 8492c145d..57e1f01ef 100644 --- a/src/proto_alpha/lib_protocol/src/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/src/TEZOS_PROTOCOL @@ -49,6 +49,7 @@ "Gas", "Script_tc_errors", "Script_ir_translator", + "Script_tc_errors_registration", "Script_interpreter", "Baking", diff --git a/src/proto_alpha/lib_protocol/src/script_ir_translator.ml b/src/proto_alpha/lib_protocol/src/script_ir_translator.ml index db020ce72..a770b00ae 100644 --- a/src/proto_alpha/lib_protocol/src/script_ir_translator.ml +++ b/src/proto_alpha/lib_protocol/src/script_ir_translator.ml @@ -2030,17 +2030,6 @@ let parse_script >>=? fun code -> return (Ex_script { code; arg_type; ret_type; storage; storage_type }) -let type_map_enc = - let open Data_encoding in - list - (conv - (fun (loc, (bef, aft)) -> (loc, bef, aft)) - (fun (loc, bef, aft) -> (loc, (bef, aft))) - (obj3 - (req "location" Script.location_encoding) - (req "stackBefore" (list Script.expr_encoding)) - (req "stackAfter" (list Script.expr_encoding)))) - let typecheck_code : context -> Script.expr -> type_map tzresult Lwt.t = fun ctxt code -> @@ -2086,525 +2075,3 @@ let hash_data typ data = let unparsed = strip_annotations @@ unparse_data typ data in let bytes = Data_encoding.Binary.to_bytes expr_encoding (Micheline.strip_locations unparsed) in Tezos_hash.Script_expr_hash.(hash_bytes [ bytes ] |> to_b58check) - -(* ---- Error registration --------------------------------------------------*) - -let ex_ty_enc = - Data_encoding.conv - (fun (Ex_ty ty) -> strip_locations (unparse_ty None ty)) - (fun expr -> - match parse_ty (root expr) with - | Ok (Ex_ty ty, _) -> Ex_ty ty - | _ -> Ex_ty Unit_t (* FIXME: ? *)) - Script.expr_encoding - -let () = - let open Data_encoding in - let located enc = - merge_objs - (obj1 (req "location" Script.location_encoding)) - enc in - let arity_enc = - int8 in - let namespace_enc = - def "primitiveNamespace" @@ - describe - ~title: "Primitive namespace" - ~description: - "One of the three possible namespaces of primitive \ - (data constructor, type name or instruction)." @@ - string_enum [ "type", Type_namespace ; - "constant", Constant_namespace ; - "instruction", Instr_namespace ] in - let kind_enc = - def "expressionKind" @@ - describe - ~title: "Expression kind" - ~description: - "One of the four possible kinds of expression \ - (integer, string, primitive application or sequence)." @@ - string_enum [ "integer", Int_kind ; - "string", String_kind ; - "primitiveApplication", Prim_kind ; - "sequence", Seq_kind ] in - let ex_stack_ty_enc = - let rec unfold = function - | Ex_stack_ty (Item_t (ty, rest, annot)) -> - (Ex_ty ty, annot) :: unfold (Ex_stack_ty rest) - | Ex_stack_ty Empty_t -> [] in - let rec fold = function - | (Ex_ty ty, annot) :: rest -> - let Ex_stack_ty rest = fold rest in - Ex_stack_ty (Item_t (ty, rest, annot)) - | [] -> Ex_stack_ty Empty_t in - conv unfold fold (list (tup2 ex_ty_enc (option string))) in - (* -- Structure errors ---------------------- *) - register_error_kind - `Permanent - ~id:"invalidArityTypeError" - ~title: "Invalid arity (typechecking error)" - ~description: - "In a script or data expression, a primitive was applied \ - to an unsupported number of arguments." - (located (obj3 - (req "primitiveName" Script.prim_encoding) - (req "expectedArity" arity_enc) - (req "wrongArity" arity_enc))) - (function - | Invalid_arity (loc, name, exp, got) -> - Some (loc, (name, exp, got)) - | _ -> None) - (fun (loc, (name, exp, got)) -> - Invalid_arity (loc, name, exp, got)) ; - register_error_kind - `Permanent - ~id:"missingScriptField" - ~title:"Script is missing a field (parse error)" - ~description: - "When parsing script, a field was expected, but not provided" - (obj1 (req "prim" prim_encoding)) - (function Missing_field prim -> Some prim | _ -> None) - (fun prim -> Missing_field prim) ; - register_error_kind - `Permanent - ~id:"duplicateScriptField" - ~title:"Script has a duplicated field (parse error)" - ~description: - "When parsing script, a field was found more than once" - (obj2 - (req "loc" location_encoding) - (req "prim" prim_encoding)) - (function Duplicate_field (loc, prim) -> Some (loc, prim) | _ -> None) - (fun (loc, prim) -> Duplicate_field (loc, prim)) ; - register_error_kind - `Permanent - ~id:"invalidPrimitiveTypeError" - ~title: "Invalid primitive (typechecking error)" - ~description: - "In a script or data expression, a primitive was unknown." - (located (obj2 - (dft "expectedPrimitiveNames" (list prim_encoding) []) - (req "wrongPrimitiveName" prim_encoding))) - (function - | Invalid_primitive (loc, exp, got) -> Some (loc, (exp, got)) - | _ -> None) - (fun (loc, (exp, got)) -> - Invalid_primitive (loc, exp, got)) ; - register_error_kind - `Permanent - ~id:"invalidExpressionKindTypeError" - ~title: "Invalid expression kind (typechecking error)" - ~description: - "In a script or data expression, an expression was of the wrong kind \ - (for instance a string where only a primitive applications can appear)." - (located (obj2 - (req "expectedKinds" (list kind_enc)) - (req "wrongKind" kind_enc))) - (function - | Invalid_kind (loc, exp, got) -> Some (loc, (exp, got)) - | _ -> None) - (fun (loc, (exp, got)) -> - Invalid_kind (loc, exp, got)) ; - register_error_kind - `Permanent - ~id:"invalidPrimitiveNamespaceTypeError" - ~title: "Invalid primitive namespace (typechecking error)" - ~description: - "In a script or data expression, a primitive was of the wrong namespace." - (located (obj3 - (req "primitiveName" prim_encoding) - (req "expectedNamespace" namespace_enc) - (req "wrongNamespace" namespace_enc))) - (function - | Invalid_namespace (loc, name, exp, got) -> Some (loc, (name, exp, got)) - | _ -> None) - (fun (loc, (name, exp, got)) -> - Invalid_namespace (loc, name, exp, got)) ; - register_error_kind - `Permanent - ~id:"unorderedMapLiteral" - ~title:"Invalid map key order" - ~description:"Map keys must be in strictly increasing order" - (obj2 - (req "location" Script.location_encoding) - (req "item" Script.expr_encoding)) - (function - | Unordered_map_keys (loc, expr) -> Some (loc, expr) - | _ -> None) - (fun (loc, expr) -> Unordered_map_keys (loc, expr)); - register_error_kind - `Permanent - ~id:"duplicateMapKeys" - ~title:"Duplicate map keys" - ~description:"Map literals cannot contain duplicated keys" - (obj2 - (req "location" Script.location_encoding) - (req "item" Script.expr_encoding)) - (function - | Duplicate_map_keys (loc, expr) -> Some (loc, expr) - | _ -> None) - (fun (loc, expr) -> Duplicate_map_keys (loc, expr)); - register_error_kind - `Permanent - ~id:"unorderedSetLiteral" - ~title:"Invalid set value order" - ~description:"Set values must be in strictly increasing order" - (obj2 - (req "location" Script.location_encoding) - (req "value" Script.expr_encoding)) - (function - | Unordered_set_values (loc, expr) -> Some (loc, expr) - | _ -> None) - (fun (loc, expr) -> Unordered_set_values (loc, expr)); - register_error_kind - `Permanent - ~id:"duplicateSetValuesInLiteral" - ~title:"Sets literals cannot contain duplicate elements" - ~description:"Set literals cannot contain duplicate elements, \ - but a duplicae was found while parsing." - (obj2 - (req "location" Script.location_encoding) - (req "value" Script.expr_encoding)) - (function - | Duplicate_set_values (loc, expr) -> Some (loc, expr) - | _ -> None) - (fun (loc, expr) -> Duplicate_set_values (loc, expr)); - (* -- Instruction typing errors ------------- *) - register_error_kind - `Permanent - ~id:"failNotInTailPositionTypeError" - ~title: "FAIL not in tail position (typechecking error)" - ~description: - "There is non trivial garbage code after a FAIL instruction." - (located empty) - (function - | Fail_not_in_tail_position loc -> Some (loc, ()) - | _ -> None) - (fun (loc, ()) -> - Fail_not_in_tail_position loc) ; - register_error_kind - `Permanent - ~id:"undefinedBinopTypeError" - ~title: "Undefined binop (typechecking error)" - ~description: - "A binary operation is called on operands of types \ - over which it is not defined." - (located (obj3 - (req "operatorName" prim_encoding) - (req "wrongLeftOperandType" ex_ty_enc) - (req "wrongRightOperandType" ex_ty_enc))) - (function - | Undefined_binop (loc, n, tyl, tyr) -> - Some (loc, (n, Ex_ty tyl, Ex_ty tyr)) - | _ -> None) - (fun (loc, (n, Ex_ty tyl, Ex_ty tyr)) -> - Undefined_binop (loc, n, tyl, tyr)) ; - register_error_kind - `Permanent - ~id:"undefinedUnopTypeError" - ~title: "Undefined unop (typechecking error)" - ~description: - "A unary operation is called on an operand of type \ - over which it is not defined." - (located (obj2 - (req "operatorName" prim_encoding) - (req "wrongOperandType" ex_ty_enc))) - (function - | Undefined_unop (loc, n, ty) -> - Some (loc, (n, Ex_ty ty)) - | _ -> None) - (fun (loc, (n, Ex_ty ty)) -> - Undefined_unop (loc, n, ty)) ; - register_error_kind - `Permanent - ~id:"badReturnTypeError" - ~title: "Bad return (typechecking error)" - ~description: - "Unexpected stack at the end of a lambda or script." - (located (obj2 - (req "expectedReturnType" ex_ty_enc) - (req "wrongStackType" ex_stack_ty_enc))) - (function - | Bad_return (loc, sty, ty) -> Some (loc, (Ex_ty ty, Ex_stack_ty sty)) - | _ -> None) - (fun (loc, (Ex_ty ty, Ex_stack_ty sty)) -> - Bad_return (loc, sty, ty)) ; - register_error_kind - `Permanent - ~id:"badStackTypeError" - ~title: "Bad stack (typechecking error)" - ~description: - "The stack has an unexpected length or contents." - (located (obj3 - (req "primitiveName" prim_encoding) - (req "relevantStackPortion" int16) - (req "wrongStackType" ex_stack_ty_enc))) - (function - | Bad_stack (loc, name, s, sty) -> Some (loc, (name, s, Ex_stack_ty sty)) - | _ -> None) - (fun (loc, (name, s, Ex_stack_ty sty)) -> - Bad_stack (loc, name, s, sty)) ; - register_error_kind - `Permanent - ~id:"inconsistentAnnotations" - ~title:"Annotations inconsistent between branches" - ~description:"The annotations on two types could not be merged" - (obj2 - (req "annot1" string) - (req "annot2" string)) - (function Inconsistent_annotations (annot1, annot2) -> Some (annot1, annot2) - | _ -> None) - (fun (annot1, annot2) -> Inconsistent_annotations (annot1, annot2)) ; - register_error_kind - `Permanent - ~id:"inconsistentTypeAnnotations" - ~title:"Types contain inconsistent annotations" - ~description:"The two types contain annotations that do not match" - (located (obj2 - (req "type1" ex_ty_enc) - (req "type2" ex_ty_enc))) - (function - | Inconsistent_type_annotations (loc, ty1, ty2) -> Some (loc, (Ex_ty ty1, Ex_ty ty2)) - | _ -> None) - (fun (loc, (Ex_ty ty1, Ex_ty ty2)) -> Inconsistent_type_annotations (loc, ty1, ty2)) ; - register_error_kind - `Permanent - ~id:"unexpectedAnnotation" - ~title:"An annotation was encountered where no annotation is expected" - ~description:"A node in the syntax tree was impropperly annotated" - (located empty) - (function Unexpected_annotation loc -> Some (loc, ()) - | _ -> None) - (fun (loc, ()) -> Unexpected_annotation loc); - register_error_kind - `Permanent - ~id:"unmatchedBranchesTypeError" - ~title: "Unmatched branches (typechecking error)" - ~description: - "At the join point at the end of two code branches \ - the stacks have inconsistent lengths or contents." - (located (obj2 - (req "firstStackType" ex_stack_ty_enc) - (req "otherStackType" ex_stack_ty_enc))) - (function - | Unmatched_branches (loc, stya, styb) -> - Some (loc, (Ex_stack_ty stya, Ex_stack_ty styb)) - | _ -> None) - (fun (loc, (Ex_stack_ty stya, Ex_stack_ty styb)) -> - Unmatched_branches (loc, stya, styb)) ; - register_error_kind - `Permanent - ~id:"badStackItemTypeError" - ~title: "Bad stack item (typechecking error)" - ~description: - "The type of a stack item is unexpected \ - (this error is always accompanied by a more precise one)." - (obj1 (req "itemLevel" int16)) - (function - | Bad_stack_item n -> Some n - | _ -> None) - (fun n -> - Bad_stack_item n) ; - register_error_kind - `Permanent - ~id:"TransferInLambdaTypeError" - ~title: "Transfer in lambda (typechecking error)" - ~description: - "A TRANSFER_TOKENS instruction was encountered in a lambda expression." - (located empty) - (function - | Transfer_in_lambda loc -> Some (loc, ()) - | _ -> None) - (fun (loc, ()) -> - Transfer_in_lambda loc) ; - register_error_kind - `Permanent - ~id:"selfInLambda" - ~title: "SELF instruction in lambda (typechecking error)" - ~description: - "A SELF instruction was encountered in a lambda expression." - (located empty) - (function - | Self_in_lambda loc -> Some (loc, ()) - | _ -> None) - (fun (loc, ()) -> - Self_in_lambda loc) ; - register_error_kind - `Permanent - ~id:"inconsistentStackLengthsTypeError" - ~title: "Inconsistent stack lengths (typechecking error)" - ~description: - "A stack was of an unexpected length \ - (this error is always in the context of a located error)." - empty - (function - | Bad_stack_length -> Some () - | _ -> None) - (fun () -> - Bad_stack_length) ; - (* -- Value typing errors ------------------- *) - register_error_kind - `Permanent - ~id:"invalidConstantTypeError" - ~title: "Invalid constant (typechecking error)" - ~description: - "A data expression was invalid for its expected type." - (located (obj2 - (req "expectedType" ex_ty_enc) - (req "wrongExpression" Script.expr_encoding))) - (function - | Invalid_constant (loc, expr, ty) -> - Some (loc, (Ex_ty ty, expr)) - | _ -> None) - (fun (loc, (Ex_ty ty, expr)) -> - Invalid_constant (loc, expr, ty)) ; - register_error_kind - `Permanent - ~id:"invalidContractTypeError" - ~title: "Invalid contract (typechecking error)" - ~description: - "A script or data expression references a contract that does not \ - exist or assumes a wrong type for an existing contract." - (located (obj1 (req "contract" Contract.encoding))) - (function - | Invalid_contract (loc, c) -> - Some (loc, c) - | _ -> None) - (fun (loc, c) -> - Invalid_contract (loc, c)) ; - register_error_kind - `Permanent - ~id:"comparableTypeExpectedTypeError" - ~title: "Comparable type expected (typechecking error)" - ~description: - "A non comparable type was used in a place where \ - only comparable types are accepted." - (located (obj1 (req "wrongType" ex_ty_enc))) - (function - | Comparable_type_expected (loc, ty) -> Some (loc, Ex_ty ty) - | _ -> None) - (fun (loc, Ex_ty ty) -> - Comparable_type_expected (loc, ty)) ; - register_error_kind - `Permanent - ~id:"InconsistentTypesTypeError" - ~title: "Inconsistent types (typechecking error)" - ~description: - "This is the basic type clash error, \ - that appears in several places where the equality of \ - two types have to be proven, it is always accompanied \ - with another error that provides more context." - (obj2 - (req "firstType" ex_ty_enc) - (req "otherType" ex_ty_enc)) - (function - | Inconsistent_types (tya, tyb) -> - Some (Ex_ty tya, Ex_ty tyb) - | _ -> None) - (fun (Ex_ty tya, Ex_ty tyb) -> - Inconsistent_types (tya, tyb)) ; - register_error_kind - `Permanent - ~id:"invalidMapBody" - ~title: "Invalid map body" - ~description: - "The body of a map block did not match the expected type" - (obj2 - (req "loc" Script.location_encoding) - (req "bodyType" ex_stack_ty_enc)) - (function - | Invalid_map_body (loc, stack) -> - Some (loc, Ex_stack_ty stack) - | _ -> None) - (fun (loc, Ex_stack_ty stack) -> - Invalid_map_body (loc, stack)) ; - register_error_kind - `Permanent - ~id:"invalidMapBlockFail" - ~title:"FAIL instruction occurred as body of map block" - ~description:"FAIL cannot be the only instruction in the body. \ - The propper type of the return list cannot be inferred." - (obj1 (req "loc" Script.location_encoding)) - (function - | Invalid_map_block_fail loc -> Some loc - | _ -> None) - (fun loc -> Invalid_map_block_fail loc) ; - register_error_kind - `Permanent - ~id:"invalidIterBody" - ~title:"ITER body returned wrong stack type" - ~description:"The body of an ITER instruction \ - must result in the same stack type as before \ - the ITER." - (obj3 - (req "loc" Script.location_encoding) - (req "befStack" ex_stack_ty_enc) - (req "aftStack" ex_stack_ty_enc)) - (function - | Invalid_iter_body (loc, bef, aft) -> Some (loc, Ex_stack_ty bef, Ex_stack_ty aft) - | _ -> None) - (fun (loc, Ex_stack_ty bef, Ex_stack_ty aft) -> Invalid_iter_body (loc, bef, aft)) ; - register_error_kind - `Permanent - ~id:"typeTooLarge" - ~title:"Stack item type too large" - ~description:"An instruction generated a type larger than the limit." - (obj3 - (req "loc" Script.location_encoding) - (req "typeSize" uint16) - (req "maximumTypeSize" uint16)) - (function - | Type_too_large (loc, ts, maxts) -> Some (loc, ts, maxts) - | _ -> None) - (fun (loc, ts, maxts) -> Type_too_large (loc, ts, maxts)) ; - (* Toplevel errors *) - register_error_kind - `Permanent - ~id:"illTypedDataTypeError" - ~title: "Ill typed data (typechecking error)" - ~description: - "The toplevel error thrown when trying to typecheck \ - a data expression against a given type \ - (always followed by more precise errors)." - (obj3 - (opt "identifier" string) - (req "expectedType" ex_ty_enc) - (req "illTypedExpression" Script.expr_encoding)) - (function - | Ill_typed_data (name, expr, ty) -> Some (name, Ex_ty ty, expr) - | _ -> None) - (fun (name, Ex_ty ty, expr) -> - Ill_typed_data (name, expr, ty)) ; - register_error_kind - `Permanent - ~id:"illFormedTypeTypeError" - ~title: "Ill formed type (typechecking error)" - ~description: - "The toplevel error thrown when trying to parse a type expression \ - (always followed by more precise errors)." - (obj3 - (opt "identifier" string) - (req "illFormedExpression" Script.expr_encoding) - (req "location" Script.location_encoding)) - (function - | Ill_formed_type (name, expr, loc) -> Some (name, expr, loc) - | _ -> None) - (fun (name, expr, loc) -> - Ill_formed_type (name, expr, loc)) ; - register_error_kind - `Permanent - ~id:"illTypedContractTypeError" - ~title: "Ill typed contract (typechecking error)" - ~description: - "The toplevel error thrown when trying to typecheck \ - a contract code against given input, output and storage types \ - (always followed by more precise errors)." - (obj2 - (req "illTypedCode" Script.expr_encoding) - (req "typeMap" type_map_enc)) - (function - | Ill_typed_contract (expr, type_map) -> - Some (expr, type_map) - | _ -> None) - (fun (expr, type_map) -> - Ill_typed_contract (expr, type_map)) diff --git a/src/proto_alpha/lib_protocol/src/script_ir_translator.mli b/src/proto_alpha/lib_protocol/src/script_ir_translator.mli index 39a64c6d6..a03b490b1 100644 --- a/src/proto_alpha/lib_protocol/src/script_ir_translator.mli +++ b/src/proto_alpha/lib_protocol/src/script_ir_translator.mli @@ -54,9 +54,6 @@ val parse_ty : val unparse_ty : string option -> 'a Script_typed_ir.ty -> Script.node -val type_map_enc : type_map Data_encoding.encoding -val ex_ty_enc : ex_ty Data_encoding.encoding - val parse_toplevel : Script.expr -> (Script.node * Script.node * Script.node * Script.node) tzresult diff --git a/src/proto_alpha/lib_protocol/src/script_tc_errors_registration.ml b/src/proto_alpha/lib_protocol/src/script_tc_errors_registration.ml new file mode 100644 index 000000000..388d75885 --- /dev/null +++ b/src/proto_alpha/lib_protocol/src/script_tc_errors_registration.ml @@ -0,0 +1,549 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2017. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +open Tezos_context +open Micheline +open Script +open Script_typed_ir +open Script_tc_errors +open Script_ir_translator + +(* Helpers for encoding *) +let type_map_enc = + let open Data_encoding in + list + (conv + (fun (loc, (bef, aft)) -> (loc, bef, aft)) + (fun (loc, bef, aft) -> (loc, (bef, aft))) + (obj3 + (req "location" Script.location_encoding) + (req "stackBefore" (list Script.expr_encoding)) + (req "stackAfter" (list Script.expr_encoding)))) + +let ex_ty_enc = + Data_encoding.conv + (fun (Ex_ty ty) -> strip_locations (unparse_ty None ty)) + (fun expr -> + match parse_ty (root expr) with + | Ok (Ex_ty ty, _) -> Ex_ty ty + | _ -> Ex_ty Unit_t (* FIXME: ? *)) + Script.expr_encoding + +(* main registration *) +let () = + let open Data_encoding in + let located enc = + merge_objs + (obj1 (req "location" Script.location_encoding)) + enc in + let arity_enc = + int8 in + let namespace_enc = + def "primitiveNamespace" @@ + describe + ~title: "Primitive namespace" + ~description: + "One of the three possible namespaces of primitive \ + (data constructor, type name or instruction)." @@ + string_enum [ "type", Type_namespace ; + "constant", Constant_namespace ; + "instruction", Instr_namespace ] in + let kind_enc = + def "expressionKind" @@ + describe + ~title: "Expression kind" + ~description: + "One of the four possible kinds of expression \ + (integer, string, primitive application or sequence)." @@ + string_enum [ "integer", Int_kind ; + "string", String_kind ; + "primitiveApplication", Prim_kind ; + "sequence", Seq_kind ] in + let ex_stack_ty_enc = + let rec unfold = function + | Ex_stack_ty (Item_t (ty, rest, annot)) -> + (Ex_ty ty, annot) :: unfold (Ex_stack_ty rest) + | Ex_stack_ty Empty_t -> [] in + let rec fold = function + | (Ex_ty ty, annot) :: rest -> + let Ex_stack_ty rest = fold rest in + Ex_stack_ty (Item_t (ty, rest, annot)) + | [] -> Ex_stack_ty Empty_t in + conv unfold fold (list (tup2 ex_ty_enc (option string))) in + (* -- Structure errors ---------------------- *) + register_error_kind + `Permanent + ~id:"invalidArityTypeError" + ~title: "Invalid arity (typechecking error)" + ~description: + "In a script or data expression, a primitive was applied \ + to an unsupported number of arguments." + (located (obj3 + (req "primitiveName" Script.prim_encoding) + (req "expectedArity" arity_enc) + (req "wrongArity" arity_enc))) + (function + | Invalid_arity (loc, name, exp, got) -> + Some (loc, (name, exp, got)) + | _ -> None) + (fun (loc, (name, exp, got)) -> + Invalid_arity (loc, name, exp, got)) ; + register_error_kind + `Permanent + ~id:"missingScriptField" + ~title:"Script is missing a field (parse error)" + ~description: + "When parsing script, a field was expected, but not provided" + (obj1 (req "prim" prim_encoding)) + (function Missing_field prim -> Some prim | _ -> None) + (fun prim -> Missing_field prim) ; + register_error_kind + `Permanent + ~id:"invalidPrimitiveTypeError" + ~title: "Invalid primitive (typechecking error)" + ~description: + "In a script or data expression, a primitive was unknown." + (located (obj2 + (dft "expectedPrimitiveNames" (list prim_encoding) []) + (req "wrongPrimitiveName" prim_encoding))) + (function + | Invalid_primitive (loc, exp, got) -> Some (loc, (exp, got)) + | _ -> None) + (fun (loc, (exp, got)) -> + Invalid_primitive (loc, exp, got)) ; + register_error_kind + `Permanent + ~id:"invalidExpressionKindTypeError" + ~title: "Invalid expression kind (typechecking error)" + ~description: + "In a script or data expression, an expression was of the wrong kind \ + (for instance a string where only a primitive applications can appear)." + (located (obj2 + (req "expectedKinds" (list kind_enc)) + (req "wrongKind" kind_enc))) + (function + | Invalid_kind (loc, exp, got) -> Some (loc, (exp, got)) + | _ -> None) + (fun (loc, (exp, got)) -> + Invalid_kind (loc, exp, got)) ; + register_error_kind + `Permanent + ~id:"invalidPrimitiveNamespaceTypeError" + ~title: "Invalid primitive namespace (typechecking error)" + ~description: + "In a script or data expression, a primitive was of the wrong namespace." + (located (obj3 + (req "primitiveName" prim_encoding) + (req "expectedNamespace" namespace_enc) + (req "wrongNamespace" namespace_enc))) + (function + | Invalid_namespace (loc, name, exp, got) -> Some (loc, (name, exp, got)) + | _ -> None) + (fun (loc, (name, exp, got)) -> + Invalid_namespace (loc, name, exp, got)) ; + register_error_kind + `Permanent + ~id:"duplicateScriptField" + ~title:"Script has a duplicated field (parse error)" + ~description: + "When parsing script, a field was found more than once" + (obj2 + (req "loc" location_encoding) + (req "prim" prim_encoding)) + (function Duplicate_field (loc, prim) -> Some (loc, prim) | _ -> None) + (fun (loc, prim) -> Duplicate_field (loc, prim)) ; + register_error_kind + `Permanent + ~id:"unorderedMapLiteral" + ~title:"Invalid map key order" + ~description:"Map keys must be in strictly increasing order" + (obj2 + (req "location" Script.location_encoding) + (req "item" Script.expr_encoding)) + (function + | Unordered_map_keys (loc, expr) -> Some (loc, expr) + | _ -> None) + (fun (loc, expr) -> Unordered_map_keys (loc, expr)); + register_error_kind + `Permanent + ~id:"duplicateMapKeys" + ~title:"Duplicate map keys" + ~description:"Map literals cannot contain duplicated keys" + (obj2 + (req "location" Script.location_encoding) + (req "item" Script.expr_encoding)) + (function + | Duplicate_map_keys (loc, expr) -> Some (loc, expr) + | _ -> None) + (fun (loc, expr) -> Duplicate_map_keys (loc, expr)); + register_error_kind + `Permanent + ~id:"unorderedSetLiteral" + ~title:"Invalid set value order" + ~description:"Set values must be in strictly increasing order" + (obj2 + (req "location" Script.location_encoding) + (req "value" Script.expr_encoding)) + (function + | Unordered_set_values (loc, expr) -> Some (loc, expr) + | _ -> None) + (fun (loc, expr) -> Unordered_set_values (loc, expr)); + register_error_kind + `Permanent + ~id:"duplicateSetValuesInLiteral" + ~title:"Sets literals cannot contain duplicate elements" + ~description:"Set literals cannot contain duplicate elements, \ + but a duplicae was found while parsing." + (obj2 + (req "location" Script.location_encoding) + (req "value" Script.expr_encoding)) + (function + | Duplicate_set_values (loc, expr) -> Some (loc, expr) + | _ -> None) + (fun (loc, expr) -> Duplicate_set_values (loc, expr)); + (* -- Instruction typing errors ------------- *) + register_error_kind + `Permanent + ~id:"failNotInTailPositionTypeError" + ~title: "FAIL not in tail position (typechecking error)" + ~description: + "There is non trivial garbage code after a FAIL instruction." + (located empty) + (function + | Fail_not_in_tail_position loc -> Some (loc, ()) + | _ -> None) + (fun (loc, ()) -> + Fail_not_in_tail_position loc) ; + register_error_kind + `Permanent + ~id:"undefinedBinopTypeError" + ~title: "Undefined binop (typechecking error)" + ~description: + "A binary operation is called on operands of types \ + over which it is not defined." + (located (obj3 + (req "operatorName" prim_encoding) + (req "wrongLeftOperandType" ex_ty_enc) + (req "wrongRightOperandType" ex_ty_enc))) + (function + | Undefined_binop (loc, n, tyl, tyr) -> + Some (loc, (n, Ex_ty tyl, Ex_ty tyr)) + | _ -> None) + (fun (loc, (n, Ex_ty tyl, Ex_ty tyr)) -> + Undefined_binop (loc, n, tyl, tyr)) ; + register_error_kind + `Permanent + ~id:"undefinedUnopTypeError" + ~title: "Undefined unop (typechecking error)" + ~description: + "A unary operation is called on an operand of type \ + over which it is not defined." + (located (obj2 + (req "operatorName" prim_encoding) + (req "wrongOperandType" ex_ty_enc))) + (function + | Undefined_unop (loc, n, ty) -> + Some (loc, (n, Ex_ty ty)) + | _ -> None) + (fun (loc, (n, Ex_ty ty)) -> + Undefined_unop (loc, n, ty)) ; + register_error_kind + `Permanent + ~id:"badReturnTypeError" + ~title: "Bad return (typechecking error)" + ~description: + "Unexpected stack at the end of a lambda or script." + (located (obj2 + (req "expectedReturnType" ex_ty_enc) + (req "wrongStackType" ex_stack_ty_enc))) + (function + | Bad_return (loc, sty, ty) -> Some (loc, (Ex_ty ty, Ex_stack_ty sty)) + | _ -> None) + (fun (loc, (Ex_ty ty, Ex_stack_ty sty)) -> + Bad_return (loc, sty, ty)) ; + register_error_kind + `Permanent + ~id:"badStackTypeError" + ~title: "Bad stack (typechecking error)" + ~description: + "The stack has an unexpected length or contents." + (located (obj3 + (req "primitiveName" prim_encoding) + (req "relevantStackPortion" int16) + (req "wrongStackType" ex_stack_ty_enc))) + (function + | Bad_stack (loc, name, s, sty) -> Some (loc, (name, s, Ex_stack_ty sty)) + | _ -> None) + (fun (loc, (name, s, Ex_stack_ty sty)) -> + Bad_stack (loc, name, s, sty)) ; + register_error_kind + `Permanent + ~id:"inconsistentAnnotations" + ~title:"Annotations inconsistent between branches" + ~description:"The annotations on two types could not be merged" + (obj2 + (req "annot1" string) + (req "annot2" string)) + (function Inconsistent_annotations (annot1, annot2) -> Some (annot1, annot2) + | _ -> None) + (fun (annot1, annot2) -> Inconsistent_annotations (annot1, annot2)) ; + register_error_kind + `Permanent + ~id:"inconsistentTypeAnnotations" + ~title:"Types contain inconsistent annotations" + ~description:"The two types contain annotations that do not match" + (located (obj2 + (req "type1" ex_ty_enc) + (req "type2" ex_ty_enc))) + (function + | Inconsistent_type_annotations (loc, ty1, ty2) -> Some (loc, (Ex_ty ty1, Ex_ty ty2)) + | _ -> None) + (fun (loc, (Ex_ty ty1, Ex_ty ty2)) -> Inconsistent_type_annotations (loc, ty1, ty2)) ; + register_error_kind + `Permanent + ~id:"unexpectedAnnotation" + ~title:"An annotation was encountered where no annotation is expected" + ~description:"A node in the syntax tree was impropperly annotated" + (located empty) + (function Unexpected_annotation loc -> Some (loc, ()) + | _ -> None) + (fun (loc, ()) -> Unexpected_annotation loc); + register_error_kind + `Permanent + ~id:"unmatchedBranchesTypeError" + ~title: "Unmatched branches (typechecking error)" + ~description: + "At the join point at the end of two code branches \ + the stacks have inconsistent lengths or contents." + (located (obj2 + (req "firstStackType" ex_stack_ty_enc) + (req "otherStackType" ex_stack_ty_enc))) + (function + | Unmatched_branches (loc, stya, styb) -> + Some (loc, (Ex_stack_ty stya, Ex_stack_ty styb)) + | _ -> None) + (fun (loc, (Ex_stack_ty stya, Ex_stack_ty styb)) -> + Unmatched_branches (loc, stya, styb)) ; + register_error_kind + `Permanent + ~id:"badStackItemTypeError" + ~title: "Bad stack item (typechecking error)" + ~description: + "The type of a stack item is unexpected \ + (this error is always accompanied by a more precise one)." + (obj1 (req "itemLevel" int16)) + (function + | Bad_stack_item n -> Some n + | _ -> None) + (fun n -> + Bad_stack_item n) ; + register_error_kind + `Permanent + ~id:"TransferInLambdaTypeError" + ~title: "Transfer in lambda (typechecking error)" + ~description: + "A TRANSFER_TOKENS instruction was encountered in a lambda expression." + (located empty) + (function + | Transfer_in_lambda loc -> Some (loc, ()) + | _ -> None) + (fun (loc, ()) -> + Transfer_in_lambda loc) ; + register_error_kind + `Permanent + ~id:"selfInLambda" + ~title: "SELF instruction in lambda (typechecking error)" + ~description: + "A SELF instruction was encountered in a lambda expression." + (located empty) + (function + | Self_in_lambda loc -> Some (loc, ()) + | _ -> None) + (fun (loc, ()) -> + Self_in_lambda loc) ; + (* Bad stack length *) + register_error_kind + `Permanent + ~id:"inconsistentStackLengthsTypeError" + ~title: "Inconsistent stack lengths (typechecking error)" + ~description: + "A stack was of an unexpected length \ + (this error is always in the context of a located error)." + empty + (function + | Bad_stack_length -> Some () + | _ -> None) + (fun () -> + Bad_stack_length) ; + (* -- Value typing errors ------------------- *) + register_error_kind + `Permanent + ~id:"invalidConstantTypeError" + ~title: "Invalid constant (typechecking error)" + ~description: + "A data expression was invalid for its expected type." + (located (obj2 + (req "expectedType" ex_ty_enc) + (req "wrongExpression" Script.expr_encoding))) + (function + | Invalid_constant (loc, expr, ty) -> + Some (loc, (Ex_ty ty, expr)) + | _ -> None) + (fun (loc, (Ex_ty ty, expr)) -> + Invalid_constant (loc, expr, ty)) ; + register_error_kind + `Permanent + ~id:"invalidContractTypeError" + ~title: "Invalid contract (typechecking error)" + ~description: + "A script or data expression references a contract that does not \ + exist or assumes a wrong type for an existing contract." + (located (obj1 (req "contract" Contract.encoding))) + (function + | Invalid_contract (loc, c) -> + Some (loc, c) + | _ -> None) + (fun (loc, c) -> + Invalid_contract (loc, c)) ; + register_error_kind + `Permanent + ~id:"comparableTypeExpectedTypeError" + ~title: "Comparable type expected (typechecking error)" + ~description: + "A non comparable type was used in a place where \ + only comparable types are accepted." + (located (obj1 (req "wrongType" ex_ty_enc))) + (function + | Comparable_type_expected (loc, ty) -> Some (loc, Ex_ty ty) + | _ -> None) + (fun (loc, Ex_ty ty) -> + Comparable_type_expected (loc, ty)) ; + register_error_kind + `Permanent + ~id:"InconsistentTypesTypeError" + ~title: "Inconsistent types (typechecking error)" + ~description: + "This is the basic type clash error, \ + that appears in several places where the equality of \ + two types have to be proven, it is always accompanied \ + with another error that provides more context." + (obj2 + (req "firstType" ex_ty_enc) + (req "otherType" ex_ty_enc)) + (function + | Inconsistent_types (tya, tyb) -> + Some (Ex_ty tya, Ex_ty tyb) + | _ -> None) + (fun (Ex_ty tya, Ex_ty tyb) -> + Inconsistent_types (tya, tyb)) ; + register_error_kind + `Permanent + ~id:"invalidMapBody" + ~title: "Invalid map body" + ~description: + "The body of a map block did not match the expected type" + (obj2 + (req "loc" Script.location_encoding) + (req "bodyType" ex_stack_ty_enc)) + (function + | Invalid_map_body (loc, stack) -> + Some (loc, Ex_stack_ty stack) + | _ -> None) + (fun (loc, Ex_stack_ty stack) -> + Invalid_map_body (loc, stack)) ; + register_error_kind + `Permanent + ~id:"invalidMapBlockFail" + ~title:"FAIL instruction occurred as body of map block" + ~description:"FAIL cannot be the only instruction in the body. \ + The propper type of the return list cannot be inferred." + (obj1 (req "loc" Script.location_encoding)) + (function + | Invalid_map_block_fail loc -> Some loc + | _ -> None) + (fun loc -> Invalid_map_block_fail loc) ; + register_error_kind + `Permanent + ~id:"invalidIterBody" + ~title:"ITER body returned wrong stack type" + ~description:"The body of an ITER instruction \ + must result in the same stack type as before \ + the ITER." + (obj3 + (req "loc" Script.location_encoding) + (req "befStack" ex_stack_ty_enc) + (req "aftStack" ex_stack_ty_enc)) + (function + | Invalid_iter_body (loc, bef, aft) -> Some (loc, Ex_stack_ty bef, Ex_stack_ty aft) + | _ -> None) + (fun (loc, Ex_stack_ty bef, Ex_stack_ty aft) -> Invalid_iter_body (loc, bef, aft)) ; + register_error_kind + `Permanent + ~id:"typeTooLarge" + ~title:"Stack item type too large" + ~description:"An instruction generated a type larger than the limit." + (obj3 + (req "loc" Script.location_encoding) + (req "typeSize" uint16) + (req "maximumTypeSize" uint16)) + (function + | Type_too_large (loc, ts, maxts) -> Some (loc, ts, maxts) + | _ -> None) + (fun (loc, ts, maxts) -> Type_too_large (loc, ts, maxts)) ; + (* Toplevel errors *) + register_error_kind + `Permanent + ~id:"illTypedDataTypeError" + ~title: "Ill typed data (typechecking error)" + ~description: + "The toplevel error thrown when trying to typecheck \ + a data expression against a given type \ + (always followed by more precise errors)." + (obj3 + (opt "identifier" string) + (req "expectedType" ex_ty_enc) + (req "illTypedExpression" Script.expr_encoding)) + (function + | Ill_typed_data (name, expr, ty) -> Some (name, Ex_ty ty, expr) + | _ -> None) + (fun (name, Ex_ty ty, expr) -> + Ill_typed_data (name, expr, ty)) ; + register_error_kind + `Permanent + ~id:"illFormedTypeTypeError" + ~title: "Ill formed type (typechecking error)" + ~description: + "The toplevel error thrown when trying to parse a type expression \ + (always followed by more precise errors)." + (obj3 + (opt "identifier" string) + (req "illFormedExpression" Script.expr_encoding) + (req "location" Script.location_encoding)) + (function + | Ill_formed_type (name, expr, loc) -> Some (name, expr, loc) + | _ -> None) + (fun (name, expr, loc) -> + Ill_formed_type (name, expr, loc)) ; + register_error_kind + `Permanent + ~id:"illTypedContractTypeError" + ~title: "Ill typed contract (typechecking error)" + ~description: + "The toplevel error thrown when trying to typecheck \ + a contract code against given input, output and storage types \ + (always followed by more precise errors)." + (obj2 + (req "illTypedCode" Script.expr_encoding) + (req "typeMap" type_map_enc)) + (function + | Ill_typed_contract (expr, type_map) -> + Some (expr, type_map) + | _ -> None) + (fun (expr, type_map) -> + Ill_typed_contract (expr, type_map)) diff --git a/src/proto_alpha/lib_protocol/src/services.ml b/src/proto_alpha/lib_protocol/src/services.ml index 4c98ba7c3..e318fecba 100644 --- a/src/proto_alpha/lib_protocol/src/services.ml +++ b/src/proto_alpha/lib_protocol/src/services.ml @@ -489,7 +489,7 @@ module Helpers = struct ~description: "Typecheck a piece of code in the current context" ~query: RPC_query.empty ~input: Script.expr_encoding - ~output: (wrap_tzerror Script_ir_translator.type_map_enc) + ~output: (wrap_tzerror Script_tc_errors_registration.type_map_enc) ~error: Data_encoding.empty RPC_path.(custom_root / "helpers" / "typecheck_code")