Sarek_parse_helpersval loc_of_ppxlib : Ppxlib.Location.t -> Sarek_ast.locConvert ppxlib location to Sarek location
val loc_to_sloc : Ppxlib.Location.t -> Sarek_ast.locA functor application inside a type path (F(X).t). flatten used to return [] for it, so the type came out named "" — and an unresolvable name is turned into an empty placeholder record by Sarek_types.type_of_type_expr, not into an error.
A labelled or optional argument in an ARROW TYPE. Ptyp_arrow's label used to be read as _, so x:int -> int and int -> int parsed to the same TEArrow — the label was dropped from the type while the corresponding parameter is refused outright by collect_fun_params.
val parse_type : Ppxlib.core_type -> Sarek_ast.type_exprParse a core_type to type_expr.
The final arm refuses rather than returning a placeholder: it used to answer TEConstr ("unknown", []) for every core_type shape not listed, and Sarek_types.type_of_type_expr maps an unrecognised constructor to TRecord (name, []) — an empty record type. So an annotation the parser could not read became a phantom type named "unknown" that unified with nothing and was reported, if at all, as a type error somewhere else (backlog-192).
val parse_record_fields :
Ppxlib.label_declaration list ->
(string * bool * Sarek_ast.type_expr) listA GADT-style constructor declaration (C : int -> t). pcd_res and pcd_vars were never read, so the return type and the existential binders were dropped and the constructor was recorded as if it had been written C of int — for a parameterised type that is a different declaration.
val parse_variant_constructors :
Ppxlib.constructor_declaration list ->
(string * Sarek_ast.type_expr option) listval extract_type_from_pattern : Ppxlib.pattern -> Sarek_ast.type_expr optionExtract type annotation from a Ppxlib pattern if present
An as alias in a BINDER position (let (p as x) = e, fun (p as x) ->). extract_name_from_pattern used to answer the alias name and throw the inner pattern away, so every name p bound was silently absent from the kernel environment and surfaced later as an unbound variable — pointing at the USE, not at the alias.
val binding_type : Ppxlib.value_binding -> Sarek_ast.type_expr optionThe declared type of a let binding, from EITHER spelling.
let (x : t) = e puts the annotation in the PATTERN (Ppat_constraint). let x : t = e — the spelling almost everything in this tree uses — puts it in pvb_constraint instead, and that field was never read: the annotation was silently dropped, so a kernel-local let sum : float = ... was typed by inference with the declared width ignored, and an annotated module constant was dropped entirely by Sarek_parse.parse_payload for want of a type (backlog-192).
Both are read here, pattern first.
Extract variable name from a Ppxlib pattern
val extract_param_from_pattern : Ppxlib.pattern -> Sarek_ast.paramExtract parameter from pparam_desc
Existential type binders on a constructor pattern (C (type a) p). The binder list in Ppat_construct's payload was read as _, so the pattern parsed as the plain C p and the locally abstract type simply was not there.
val parse_pattern : Ppxlib.pattern -> Sarek_ast.patternParse a Ppxlib pattern to Sarek pattern
val parse_binop : string -> Sarek_ast.binop optionParse a binary operator
val parse_unop : string -> Sarek_ast.unop optionParse a unary operator
module To_502 : sig ... endmodule From_502 : sig ... endAn annotation with fewer arrows than the function has parameters. Shared between the two places that put a declared type into a RESULT slot.
val peel_arrows : int -> Sarek_ast.type_expr -> Sarek_ast.type_expr optionStrip n leading arrows off a type, or None if it has fewer than n.
val fun_return_type : Ppxlib.expression -> Sarek_ast.type_expr optionThe declared RESULT type of a function expression, if it has one.
Pexp_function's type_constraint option slot is where OCaml >= 5.1 puts the : t of let f (x : int32) : int32 = ... — NOT in the pattern. It was read as _ by collect_fun_params, so every kernel helper's declared return type was silently discarded and the helper's result type came from inference alone (backlog-192).
EVERY Pexp_function on the way down is inspected, not just the outermost. An earlier revision of this function read only the outermost and justified it by saying a nested one "belongs to that inner function and not to the binding" — which is false, because collect_fun_params below DESCENDS through Pfunction_body and merges the inner function's parameters into the binding's list. After that flattening there is no inner function left for the annotation to belong to, and let f (x : int32) = fun (y : int32) : float32 -> ... had its float32 dropped while the flattened spelling of the same function had it honoured. Measured: the two spellings compiled to different verdicts, exit 0 versus a unification error.
The LAST constraint on the way down wins, and it is peeled by the number of parameters collected AFTER it — because a constraint sitting above further parameters describes a FUNCTION type, not the flattened result. let f (x : int32) : (int32 -> int32) = fun (y : int32) -> y therefore yields int32, not the arrow. Too few arrows is refused rather than half-applied.
val collect_fun_params :
Ppxlib.expression ->
Ppxlib.pattern list * fun_body option