Patterns
Partly written. §1 to §4 were written with milestone M3 of the Lyric 5 plan (slices S4 to S6), the type patterns with M4, the type-set pattern with the catch-up block N (N2c), a built-in type in both with M8c S15, spec-first: each rule lands here with its conformance case before or with its implementation. Source of the decisions: 08 Syntax Y6, 03 Type system T9.
Scope
Literal, binding (a bare name always binds), variant (.Red), field, tuple, array with rest, type and or patterns; exhaustiveness.
Conformance. conformance/cases/09-patterns/.
1. Where a pattern stands
- A pattern stands in an arm of
match, afterletorvarin a binding (let .Num(n) = s else { … };, 07), and inif (let P = e)andwhile (let P = e). - A pattern is tried against the scrutinee; it matches or it does not, and when it matches its bindings hold parts of the value. A pattern that matches every value of the scrutinee's type is irrefutable.
- The arms of a
matchare tried in the order they are written, and the first that matches wins. An arm may carry a guard,Pattern if expr, evaluated with the pattern's bindings in scope only when the pattern matched; the arm is taken only when the guard istrue. - In a binding,
letorvarbefore the pattern decides the mutability of all its bindings. A binding copies the part it names, as any binding does (03 §2.1): writing through avarbinding of a struct payload leaves the scrutinee as it was; a reference bound is the object. let P = e else { … };binds the names ofPwhen it matches and runs the block otherwise; the block leaves — byreturn,throw,break,continueor a panic — on every path, or the statement is refused (LYR-SEM0098), since after it the names are bound. Withoutelsethe pattern is irrefutable, or the statement is refused. Anif (let P = e)whose pattern is irrefutable is a warning (LYR-SEM0104).
2. The forms
- Wildcard.
_matches every value and binds nothing. - Binding. A bare name binds the whole value it stands against, always, whatever the
name spells. A bare name that spells a variant of the scrutinee's enum is refused
(
LYR-SEM0111), and the diagnostic names the two forms that test the variant: it would otherwise match every value under the variant's name, and a typo in a variant would match in silence. - Literal. An integer, float, character, string,
boolornullliteral matches the value equal to it, by the equality of the scrutinee's type; a negative number literal is a literal. Anullliteral stands against an optional only (03 §3.2). A float literal never matches NaN. - Range.
a..banda..=bover integer and character literals match the values of the range,-5..=-1included. - Variant.
.Red,.Num(v)and.Rect { w = 0, h }match one variant of the scrutinee's enum, the enum unnamed (03 §4.2); the qualifiedSignal.Red,Shape.Num(v)andShape.Rect { … }say the same with the enum named, and both forms may stand in onematch. A tuple variant's pattern has one sub-pattern per payload element. A struct variant's pattern names fields:w = Ptests the fieldwagainstP, and a barehbinds the fieldhto the nameh. A field left out is not read; the pattern may leave fields out. A name the variant does not have, a payload form the variant does not have and a variant the enum does not have are refused (LYR-SEM0015,LYR-SEM0031,LYR-SEM0029). The dotted form on a scrutinee that is no enum is refused (LYR-SEM0029). - Field.
Point { x = 0, y }over a struct or a class names the type the scrutinee already has, reads the fields it names and no others, and matches when every field pattern does.Point { x, y }tests nothing and is irrefutable. - Or.
P | Qmatches when either alternative does; the alternatives are tried in order. Every alternative binds the same names at the same types (LYR-SEM0032). - A name binds once in a pattern (
LYR-SEM0097):.Rect { w = n, h = n }is refused, not read as one of its halves. An or-pattern's alternatives repeat the names by rule. - A pattern tests and binds at every depth:
.Some(.Num(n)),.Rect { w = 0 }inside an or-pattern, a literal under a field. There is no depth at which a form is refused for being nested. - Array.
[a, b, c]matches an array, a view or an inline array (03 §5) of exactly that many elements, each against its pattern;[first, ..rest],[.., last]and[first, .., last]match one long enough for the elements beside the rest. At most one rest stands in a pattern, and..restbinds a view of the elements it covers — aSlice<T>, sharing them, never a copy. - Tuple.
(a, _)matches a tuple (03 §6) of that many elements, each against its pattern;let (a, b) = t;binds through the same pattern, and a nested tuple is taken apart in place:((a, b), c). The arity is the type's, or the pattern is refused (LYR-SEM0029). - Type.
c: Circleand_: Circlestand against an interface value and match when it holds a value of that type (05 §9);cbinds that value as that type — the object for a class, a copy for a struct, an enum or a built-in's value; the type may be a built-in one (n: int), tested exactly asistests it (05 §9 rule 2). On a scrutinee whose type is no interface the pattern is refused (LYR-SEM0131): the static type answers already. - Type set (08 Y6; N2c).
s in [Circle, Rect]and_ in [Circle, Rect]stand against an interface value and match when it holds a value of one of the types, tested in order — the form ofcatch (e in [A, B])(06 §4), under the same list rule: one type bare,s in Circle, several in brackets, an empty list refused (LYR-PAR0049).sbinds as the one type of a set of one, ass: Circledoes; of a larger set it binds the interface value itself, which carries the set as a catch binding does (05 K7): amatchover aletbinding of it is exhaustive with an arm per type, and athrowof it throws the set. On a scrutinee whose type is no interface the pattern is refused (LYR-SEM0131).
3. Exhaustiveness
- A
matchis exhaustive: its arms cover every value of the scrutinee's type, or thematchis refused (LYR-SEM0050). The diagnostic names a witness: a value no arm matches, written the way a pattern is written —.Rect { … },.Some(false),null— so that what it names can be added as an arm. - The values are enumerated for an enum (its variants, each with its payload enumerated in
turn), for
bool(true,false) and for an optional (nulland the values of the inner type); a field pattern enumerates through its fields. An array or a view is enumerated by its length classes: an arm whose fixed positions all bind without testing covers its length, or every length from there up when it carries a rest, and the witness is the smallest length nothing covers; an inline array has one length. A tuple is enumerated through its columns: the arms cover it when every combination of the elements' values does, and the witness is written as a tuple. Every other type —int,string,float,char, a class — is open and needs a_or a binding arm. - A guarded arm covers nothing: whether its guard holds is not known to the check.
- A scrutinee of type
?Eadmitsnulland the variants ofEin onematch; presence is established before a variant is examined, and the arms are still tried in order. - An enum or a sealed interface that carries
@NonExhaustiveis open outside the package that declares it (11 §1 rule 12): there amatchover it needs a_or a binding arm, whatever its other arms cover — a later version may add to it.
A type pattern covers one conformer, a type-set pattern each of its types. Over an open interface the set of conformers is open, so a
match of type patterns needs _ (LYR-SEM0050); over a sealed interface
(05 §10) the set is closed, and unguarded type
patterns for every conformer make the match exhaustive — the diagnostic names the conformer
missing as the pattern to add, _: Rect.
4. Unreachable arms
- An arm no value can reach is a warning (
LYR-SEM0112), not an error: every arm after an unguarded arm that is irrefutable, and an unguarded arm that repeats a unit variant, a literal ornullan unguarded arm above already tests. A payload pattern and a guarded arm keep a case open. - Together with §2.2, a misspelt variant in a bare name gets two messages and no silent way through: the binding it would be is refused when the spelling is a variant, and shadows the arms below it — reported as unreachable — when it is not.