Skip to content

Revert <: Product requierment in pattern matching #2249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import scala.collection.{ mutable, immutable }
import PartialFunction._
import collection.mutable
import util.common.alwaysZero
import typer.Applications

object Definitions {

Expand Down Expand Up @@ -846,6 +845,9 @@ class Definitions {
TupleType(elems.size).appliedTo(elems)
}

def isProductSubType(tp: Type)(implicit ctx: Context) =
tp.derivesFrom(ProductType.symbol)

/** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN? */
def isFunctionType(tp: Type)(implicit ctx: Context) = {
val arity = functionArity(tp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1408,7 +1408,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
protected def seqTree(binder: Symbol) = tupleSel(binder)(firstIndexingBinder + 1)
protected def tupleSel(binder: Symbol)(i: Int): Tree = {
val accessors =
if (Applications.canProductMatch(binder.info))
if (defn.isProductSubType(binder.info))
productSelectors(binder.info)
else binder.caseAccessors
val res =
Expand Down
7 changes: 2 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ object Applications {
ref.info.widenExpr.dealias
}

def canProductMatch(tp: Type)(implicit ctx: Context) =
extractorMemberType(tp, nme._1).exists

/** Does `tp` fit the "product match" conditions as an unapply result type
* for a pattern with `numArgs` subpatterns?
* This is the case of `tp` has members `_1` to `_N` where `N == numArgs`.
Expand All @@ -72,7 +69,7 @@ object Applications {
}

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

def productSelectors(tp: Type)(implicit ctx: Context): List[Symbol] = {
val sels = for (n <- Iterator.from(0)) yield tp.member(nme.selectorName(n)).symbol
Expand Down Expand Up @@ -114,7 +111,7 @@ object Applications {
getUnapplySelectors(getTp, args, pos)
else if (unapplyResult isRef defn.BooleanClass)
Nil
else if (canProductMatch(unapplyResult))
else if (defn.isProductSubType(unapplyResult))
productSelectorTypes(unapplyResult)
// this will cause a "wrong number of arguments in pattern" error later on,
// which is better than the message in `fail`.
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
/** Is `formal` a product type which is elementwise compatible with `params`? */
def ptIsCorrectProduct(formal: Type) = {
isFullyDefined(formal, ForceDegree.noBottom) &&
Applications.canProductMatch(formal) &&
defn.isProductSubType(formal) &&
Applications.productSelectorTypes(formal).corresponds(params) {
(argType, param) =>
param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe
Expand Down
37 changes: 37 additions & 0 deletions tests/run/1938-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
object ProdNonEmpty {
def _1: Int = 0
def _2: String = "???" // Slight variation with scalac: this test passes
// with ??? here. I think dotty behavior is fine
// according to the spec given that methods involved
// in pattern matching should be pure.
def isEmpty = false
def unapply(s: String): this.type = this
def get = this
}

object ProdEmpty {
def _1: Int = ???
def _2: String = ???
def isEmpty = true
def unapply(s: String): this.type = this
def get = this
}

object Test {
def main(args: Array[String]): Unit = {
"" match {
case ProdNonEmpty(0, _) => ()
case _ => ???
}

"" match {
case ProdNonEmpty(1, _) => ???
case _ => ()
}

"" match {
case ProdEmpty(_, _) => ???
case _ => ()
}
}
}