Skip to content

Commit b8ed254

Browse files
authored
Merge pull request #2249 from dotty-staging/revert-product
Revert <: Product requierment in pattern matching
2 parents 46e3395 + 3e04b6f commit b8ed254

File tree

5 files changed

+44
-8
lines changed

5 files changed

+44
-8
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import scala.collection.{ mutable, immutable }
1010
import PartialFunction._
1111
import collection.mutable
1212
import util.common.alwaysZero
13-
import typer.Applications
1413

1514
object Definitions {
1615

@@ -846,6 +845,9 @@ class Definitions {
846845
TupleType(elems.size).appliedTo(elems)
847846
}
848847

848+
def isProductSubType(tp: Type)(implicit ctx: Context) =
849+
tp.derivesFrom(ProductType.symbol)
850+
849851
/** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN? */
850852
def isFunctionType(tp: Type)(implicit ctx: Context) = {
851853
val arity = functionArity(tp)

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
14081408
protected def seqTree(binder: Symbol) = tupleSel(binder)(firstIndexingBinder + 1)
14091409
protected def tupleSel(binder: Symbol)(i: Int): Tree = {
14101410
val accessors =
1411-
if (Applications.canProductMatch(binder.info))
1411+
if (defn.isProductSubType(binder.info))
14121412
productSelectors(binder.info)
14131413
else binder.caseAccessors
14141414
val res =

compiler/src/dotty/tools/dotc/typer/Applications.scala

+2-5
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ object Applications {
4848
ref.info.widenExpr.dealias
4949
}
5050

51-
def canProductMatch(tp: Type)(implicit ctx: Context) =
52-
extractorMemberType(tp, nme._1).exists
53-
5451
/** Does `tp` fit the "product match" conditions as an unapply result type
5552
* for a pattern with `numArgs` subpatterns?
5653
* This is the case of `tp` has members `_1` to `_N` where `N == numArgs`.
@@ -72,7 +69,7 @@ object Applications {
7269
}
7370

7471
def productArity(tp: Type)(implicit ctx: Context) =
75-
if (canProductMatch(tp)) productSelectorTypes(tp).size else -1
72+
if (defn.isProductSubType(tp)) productSelectorTypes(tp).size else -1
7673

7774
def productSelectors(tp: Type)(implicit ctx: Context): List[Symbol] = {
7875
val sels = for (n <- Iterator.from(0)) yield tp.member(nme.selectorName(n)).symbol
@@ -114,7 +111,7 @@ object Applications {
114111
getUnapplySelectors(getTp, args, pos)
115112
else if (unapplyResult isRef defn.BooleanClass)
116113
Nil
117-
else if (canProductMatch(unapplyResult))
114+
else if (defn.isProductSubType(unapplyResult))
118115
productSelectorTypes(unapplyResult)
119116
// this will cause a "wrong number of arguments in pattern" error later on,
120117
// which is better than the message in `fail`.

compiler/src/dotty/tools/dotc/typer/Typer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
759759
/** Is `formal` a product type which is elementwise compatible with `params`? */
760760
def ptIsCorrectProduct(formal: Type) = {
761761
isFullyDefined(formal, ForceDegree.noBottom) &&
762-
Applications.canProductMatch(formal) &&
762+
defn.isProductSubType(formal) &&
763763
Applications.productSelectorTypes(formal).corresponds(params) {
764764
(argType, param) =>
765765
param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe

tests/run/1938-2.scala

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
object ProdNonEmpty {
2+
def _1: Int = 0
3+
def _2: String = "???" // Slight variation with scalac: this test passes
4+
// with ??? here. I think dotty behavior is fine
5+
// according to the spec given that methods involved
6+
// in pattern matching should be pure.
7+
def isEmpty = false
8+
def unapply(s: String): this.type = this
9+
def get = this
10+
}
11+
12+
object ProdEmpty {
13+
def _1: Int = ???
14+
def _2: String = ???
15+
def isEmpty = true
16+
def unapply(s: String): this.type = this
17+
def get = this
18+
}
19+
20+
object Test {
21+
def main(args: Array[String]): Unit = {
22+
"" match {
23+
case ProdNonEmpty(0, _) => ()
24+
case _ => ???
25+
}
26+
27+
"" match {
28+
case ProdNonEmpty(1, _) => ???
29+
case _ => ()
30+
}
31+
32+
"" match {
33+
case ProdEmpty(_, _) => ???
34+
case _ => ()
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)