Melange_compiler_libs.Parmatch
Detection of partial matches and unused match cases.
type parmatch_case('pattern) = {
pattern: 'pattern,
has_guard: bool,
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);
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
Exported compatibility functor, abstracted over constructor equality
let lub: Typedtree.pattern => Typedtree.pattern => Typedtree.pattern;
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 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 pat_of_constr:
Typedtree.pattern =>
Types.constructor_description =>
Typedtree.pattern;
let complete_constrs:
Typedtree.pattern_data(Types.constructor_description) =>
list(Types.constructor_description) =>
list(Types.constructor_description);
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:
Pat_any
)tp
)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;
let check_partial:
(Typedtree.pattern => option(Typedtree.pattern)) =>
Location.t =>
list(typed_case(Typedtree.value)) =>
Typedtree.partial;
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;