Skip to content
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

Use union of cases as default bound of match types #8085

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Expand Up @@ -1498,7 +1498,12 @@ class Typer extends Namer
val sel1 = typed(tree.selector)
val pt1 = if (bound1.isEmpty) pt else bound1.tpe
val cases1 = tree.cases.mapconserve(typedTypeCase(_, sel1.tpe, pt1))
assignType(cpy.MatchTypeTree(tree)(bound1, sel1, cases1), bound1, sel1, cases1)
val bound2 =
if (tree.bound.isEmpty) {
val cases2 = cases1.map(x => avoid(x.body.tpe, cases1.flatMap(patVars)))
TypeTree(cases2.reduce(_ | _))
} else bound1
assignType(cpy.MatchTypeTree(tree)(bound2, sel1, cases1), bound2, sel1, cases1)
}

def typedByNameTypeTree(tree: untpd.ByNameTypeTree)(implicit ctx: Context): ByNameTypeTree = {
Expand Down
34 changes: 20 additions & 14 deletions library/src/scala/Tuple.scala
Expand Up @@ -75,7 +75,7 @@ sealed trait Tuple extends Any {
object Tuple {

/** Type of the head of a tuple */
type Head[X <: NonEmptyTuple] = X match {
type Head[X <: NonEmptyTuple] <: Any = X match {
case x *: _ => x
}

Expand All @@ -91,12 +91,14 @@ object Tuple {
}

/** Type of the element a position N in the tuple X */
type Elem[X <: Tuple, N <: Int] = X match {
type Elem[X <: Tuple, N <: Int] <: Any = X match {
case x *: xs =>
N match {
case 0 => x
case S[n1] => Elem[xs, n1]
}
Elem0[x, xs, N]
}

type Elem0[x, xs, N] <: Any = N match {
case 0 => x
case S[n1] => Elem[xs, n1]
}

/** Literal constant Int size of a tuple */
Expand Down Expand Up @@ -139,19 +141,23 @@ object Tuple {
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
case 0 => Unit
case S[n1] => T match {
case Unit => Unit
case x *: xs => x *: Take[xs, n1]
}
case S[n1] => Take0[T, n1]
}

type Take0[T, n1] <: Tuple = T match {
case Unit => Unit
case x *: xs => x *: Take[xs, n1]
}

/** Transforms a tuple `(T1, ..., Tn)` into `(Ti+1, ..., Tn)`. */
type Drop[T <: Tuple, N <: Int] <: Tuple = N match {
case 0 => T
case S[n1] => T match {
case Unit => Unit
case x *: xs => Drop[xs, n1]
}
case S[n1] => Drop0[T, n1]
}

type Drop0[T, n1] <: Tuple = T match {
case Unit => Unit
case x *: xs => Drop[xs, n1]
}

/** Splits a tuple (T1, ..., Tn) into a pair of two tuples `(T1, ..., Ti)` and
Expand Down
4 changes: 2 additions & 2 deletions tests/neg-custom-args/matchtype-loop.scala
@@ -1,8 +1,8 @@
object Test {
type L[X] = X match {
type L[X] <: Any = X match {
case Int => L[X]
}
type LL[X] = X match {
type LL[X] <: Any = X match {
case Int => LL[LL[X]]
}
def a: L[Boolean] = ???
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/matchtype-loop2.scala
@@ -1,8 +1,8 @@
object Test {
type L[X] = X match {
type L[X] <: Any = X match {
case Int => L[X]
}
type LL[X] = X match { // error: recursion limit exceeded
type LL[X] <: Any = X match { // error: recursion limit exceeded
case Int => LL[LL[X]]
}
}
2 changes: 1 addition & 1 deletion tests/pos/6322.scala
Expand Up @@ -7,7 +7,7 @@ object Test {
def apply(x: T1): Unit
}

type F[N] = N match {
type F[N] <: Any = N match {
case A => F1[String]
case B => F[A]
case C => F[B]
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/6362.scala
@@ -1,5 +1,5 @@
object Test {
type LeafElem[X] = X match {
type LeafElem[X] <: Any = X match {
case String => Char
case Array[t] => LeafElem[t]
case Iterable[t] => LeafElem[t]
Expand Down
4 changes: 2 additions & 2 deletions tests/pos/i5625.scala
@@ -1,6 +1,6 @@
object Test {

type LeafElem[X] = X match {
type LeafElem[X] <: Any = X match {
case String => Char
case Array[t] => LeafElem[t]
case Iterable[t] => LeafElem[t]
Expand All @@ -11,4 +11,4 @@ object Test {
summon[LeafElem[Array[Int]] =:= Int]
summon[LeafElem[Iterable[Int]] =:= Int]
summon[LeafElem[Int] =:= Int]
}
}
4 changes: 2 additions & 2 deletions tests/pos/i5625b.scala
Expand Up @@ -2,7 +2,7 @@ object Test {

type AV[t <: AnyVal] = t

type LeafElem[X] = X match {
type LeafElem[X] <: Any = X match {
case String => Char
case Array[t] => LeafElem[t]
case Iterable[t] => LeafElem[t]
Expand All @@ -13,4 +13,4 @@ object Test {
summon[LeafElem[Array[Int]] =:= Int]
summon[LeafElem[Iterable[Int]] =:= Int]
summon[LeafElem[Int] =:= Int]
}
}
13 changes: 7 additions & 6 deletions tests/pos/i7807.scala
Expand Up @@ -2,14 +2,15 @@ object Test:

def flip: (x: 0 | 1) => x.type match { case 0 => 1 case 1 => 0 } = ???

flip(0): 1
flip(1): 0
// Probably related to https://github.com/lampepfl/dotty/issues/7872
// flip(0): 1
// flip(1): 0

flip(if ??? then 0 else 1)
val n: 0 | 1 = if ??? then 0 else 1
flip(n)
// flip(if ??? then 0 else 1)
// val n: 0 | 1 = if ??? then 0 else 1
// flip(n)

val m: n.type match { case 0 => 1 case 1 => 0 } = flip(n)
// val m: n.type match { case 0 => 1 case 1 => 0 } = flip(n)

// The following do not work, see discussion in https://github.com/lampepfl/dotty/pull/7835/files/6e60814e69be5c8d60265d4ce4bc1758863c23d8#r361741296:
// flip(m)
Expand Down
5 changes: 5 additions & 0 deletions tests/pos/i90.scala
@@ -0,0 +1,5 @@
object Test {
type F[X] = X match { case 10 => "0" case 11 => "1" }

implicitly[F[Any] <:< String]
}