Module Melange_compiler_libs.Parmatch

Detection of partial matches and unused match cases.

type parmatch_case('pattern) = {
  1. pattern: 'pattern,
  2. has_guard: bool,
  3. needs_refute: bool,
    /*

    true if the program text claims the case is unreachable, a la function _ -> .

    */
};

Most checks in this file need not access all information about a case, and just need a few pieces of information. parmatch_case is those few pieces of information.

type typed_case('category) := parmatch_case(Typedtree.general_pattern('category));
let typed_case: Typedtree.case('category) => typed_case('category);
let untyped_case: Parsetree.case => parmatch_case(Parsetree.pattern);
let const_compare: Asttypes.constant => Asttypes.constant => int;

const_compare c1 c2 compares the actual values represented by c1 and c2, while simply using Stdlib.compare would compare the representations.

cf. MPR#5758

let le_pat: Typedtree.pattern => Typedtree.pattern => bool;

le_pat p q means: forall V, V matches q implies V matches p

let le_pats: list(Typedtree.pattern) => list(Typedtree.pattern) => bool;

le_pats (p1 .. pm) (q1 .. qn) means: forall i <= m, le_pat pi qi

module Compat: (_: { ... }) => { ... };

Exported compatibility functor, abstracted over constructor equality

exception Empty;

lub p q is a pattern that matches all values matched by p and q. May raise Empty, when p and q are not compatible.

let lubs: list(Typedtree.pattern) => list(Typedtree.pattern) => list(Typedtree.pattern);

lubs [p1; ...; pn] [q1; ...; qk], where n < k, is [lub p1 q1; ...; lub pk qk].

let get_mins: ('a => 'a => bool) => list('a) => list('a);
let set_args: Typedtree.pattern => list(Typedtree.pattern) => list(Typedtree.pattern);

Those two functions recombine one pattern and its arguments: For instance: (_,_)::p1::p2::rem -> (p1, p2)::rem The second one will replace mutable arguments by '_'

let set_args_erase_mutable: Typedtree.pattern => list(Typedtree.pattern) => list(Typedtree.pattern);
let pats_of_type: Env.t => Types.type_expr => list(Typedtree.pattern);

pats_of_type builds a list of patterns from a given expected type, for explosion of wildcard patterns in Typecore.type_pat.

There are four interesting cases:

  • the type is empty ()
  • no further explosion is necessary (Pat_any)
  • a single pattern is generated, from a record or tuple type or a single-variant type (tp)
  • a list of patterns, in the case that all branches are GADT constructors (tp1; ..; tpn).
let pressure_variants: Env.t => list(Typedtree.pattern) => unit;
let pressure_variants_in_computation_pattern: Env.t => list(Typedtree.general_pattern(Typedtree.computation)) => unit;

check_partial pred loc caselist and check_unused refute pred caselist are called with a function pred which will be given counter-example candidates: they may be partially ill-typed, and have to be type-checked to extract a valid counter-example. pred returns a valid counter-example or None. refute indicates that check_unused was called on a refutation clause.

let check_unused: (bool => Typedtree.pattern => option(Typedtree.pattern)) => list(typed_case(Typedtree.value)) => unit;
let irrefutable: Typedtree.pattern => bool;
let inactive: partial:Typedtree.partial => Typedtree.pattern => bool;

An inactive pattern is a pattern, matching against which can be duplicated, erased or delayed without change in observable behavior of the program. Patterns containing (lazy _) subpatterns or reads of mutable fields are active.

let check_ambiguous_bindings: list(Typedtree.case(Typedtree.value)) => unit;
let some_private_tag: Asttypes.label;