Description
This is an attempt to come up with a sane set of rules for name-based pattern matching. To recall: In dotty, name-based is all we have, there is no special treatment of type classes anymore.
The purpose of the rules is, given a pattern P(P1, .., Pn)
, to produce the expected types PT1,..., PTn
against which the argument patterns P1, .., Pn
will be matched. Let X
be the expected type of the whole pattern match.
-
If the companion object
P
contains a memberdef unapply(x: T): U
such thatX
conforms toT
then-
If
U
is a subtype of a product typeProduct{n}[T1, ... Tn]
with arityn
thenPTi = Ti
, fori = 1,..,n
. -
If
U
has parameterless (def
orval
) membersisEmpty: Boolean
andget: V
,
then:- if there is exactly one argument (P1) then
PT1 = V
. - if there are zero or more than one arguments, then
V
must derive from a product type
Product{n}[V1, ..., Vn]
andPTi = Vi
, fori = 1,..,n
.
- if there is exactly one argument (P1) then
-
If
U
is of typeBoolean
andn = 0
, OK -
Otherwise error.
-
-
If the precondition (1) does not hold (i.e. no
unapply
method with the right argument type), but the companion objectP
contains a memberdef unapplySeq(x: T): U
whereX
conforms toT
then- If
U
derives fromSeq[V]
for some typeV
, thenPTi = V
fori = 1,..,n
, orPTn = V*
ifPn
is a repeated parameter. - If
U
has parameterless (def
orval
) membersisEmpty: Boolean
andget: S
,
whereS <: Seq[V]
for some typeV
, thenPTi = V
fori = 1,..,n
, orPTn = V*
ifPn
is a repeated parameter. - Otherwise error.
- If
Note 1: There are some subtleties with overloading which are skimmed over here. See the comment of typer.Applications#trySelectUnapply for a more detailed explanation.
Note 2: A consequence of the rules is that a selector type may match patterns of different arities using the same unapply
. One arity could trigger a product based selection (using rule 1.i), the other a get/isEmpty selection (using rule 1.ii). Scala parser combinators actually exercise that functionality. A test case is in pos/Patterns.scala
.