Skip to content

Commit b9047d9

Browse files
committed
Check MatchType tree case bodies
1 parent de4ad2b commit b9047d9

19 files changed

+109
-35
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ object TypeEval:
2121
case tp: TypeProxy =>
2222
val tp1 = tp.superType
2323
if tp1.isStable then tp1.fixForEvaluation else tp
24+
case AndType(tp1: ConstantType, tp2) if tp1.frozen_<:<(tp2) => tp1
2425
case tp => tp
2526

2627
def constValue(tp: Type): Option[Any] = tp.fixForEvaluation match

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5024,7 +5024,7 @@ object Types {
50245024
record("MatchType.reduce computed")
50255025
if (myReduced != null) record("MatchType.reduce cache miss")
50265026
myReduced =
5027-
trace(i"reduce match type $this $hashCode", matchTypes, show = true)(inMode(Mode.Type) {
5027+
trace(i"reduce match type $this $hashCode", matchTypes, show = true)(withMode(Mode.Type) {
50285028
def matchCases(cmp: TrackingTypeComparer): Type =
50295029
val saved = ctx.typerState.snapshot()
50305030
try cmp.matchCases(scrutinee.normalized, cases)

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,12 +483,16 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
483483
// case x: (_: Tree[?])
484484
case m @ MatchTypeTree(bounds, selector, cases) =>
485485
// Analog to the case above for match types
486-
def transformIgnoringBoundsCheck(x: CaseDef): CaseDef =
487-
withMode(Mode.Pattern)(super.transform(x)).asInstanceOf[CaseDef]
486+
def transformCase(x: CaseDef): CaseDef =
487+
cpy.CaseDef(tree)(
488+
withMode(Mode.Pattern)(transform(x.pat)),
489+
transform(x.guard),
490+
transform(x.body),
491+
)
488492
cpy.MatchTypeTree(tree)(
489493
super.transform(bounds),
490494
super.transform(selector),
491-
cases.mapConserve(transformIgnoringBoundsCheck)
495+
cases.mapConserve(transformCase)
492496
)
493497
case Block(_, Closure(_, _, tpt)) if ExpandSAMs.needsWrapperClass(tpt.tpe) =>
494498
superAcc.withInvalidCurrentClass(super.transform(tree))

library/src/scala/Tuple.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,13 @@ object Tuple {
147147
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
148148
type Map[Tup <: Tuple, F[_ <: Union[Tup]]] <: Tuple = Tup match {
149149
case EmptyTuple => EmptyTuple
150-
case h *: t => F[h] *: Map[t, F]
150+
case h *: t => F[h & Union[Tup]] *: Map[t, [x <: Union[t]] =>> F[x & Union[Tup]]]
151151
}
152152

153153
/** Converts a tuple `(T1, ..., Tn)` to a flattened `(..F[T1], ..., ..F[Tn])` */
154154
type FlatMap[Tup <: Tuple, F[_ <: Union[Tup]] <: Tuple] <: Tuple = Tup match {
155155
case EmptyTuple => EmptyTuple
156-
case h *: t => Concat[F[h], FlatMap[t, F]]
156+
case h *: t => Concat[F[h & Union[Tup]], FlatMap[t, [x <: Union[t]] =>> F[x & Union[Tup]]]]
157157
}
158158

159159
/** Filters out those members of the tuple for which the predicate `P` returns `false`.

tests/neg/i15272.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
case class Head[+NT, +From <: NT, +To <: NT] (from: From, to: To ) extends EdgeN[NT]
44
case class Cons[+NT, +From <: NT, +ToE <: EdgeN[NT]](from: From, to: ToE) extends EdgeN[NT]
55
final type InNodesTupleOf[NT, E <: EdgeN[NT]] <: Tuple = E match
6-
case Cons[nt,from,toE] => from *: InNodesTupleOf[nt,toE]
6+
case Cons[nt,from,toE] => from *: InNodesTupleOf[nt,toE] // error
77
case Head[nt,from ,to] => from *: EmptyTuple
88
def inNodesTuple[NT,E <: EdgeN[NT]](edge: E): InNodesTupleOf[NT,E] = edge match
99
case e: Cons[nt,from,toE] => e.from *: inNodesTuple[nt,toE](e.to) // error
1010
case e: Head[nt,from,to] => e.from *: EmptyTuple
11-
end EdgeN
11+
end EdgeN

tests/pos/10867.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
object Test {
2+
// e.g inserts[z, (a, b)] =:= ((z, a, b), (a, z, b), (a, b, z))
23
type inserts[a, as <: Tuple] <: Tuple =
34
as match
45
case EmptyTuple => (a *: EmptyTuple) *: EmptyTuple
5-
case y *: ys => (a *: y *: ys) *: Tuple.Map[inserts[a, ys], [t <: Tuple] =>> y *: t]
6+
case y *: ys => (a *: y *: ys) *: Tuple.Map[inserts[a, ys], [t] =>> y *: (t & Tuple)]
67

78
type inserts2[a] =
89
[as <: Tuple] =>> inserts[a, as]

tests/pos/13633.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ object Sums extends App:
3838
case false => A
3939
case true => Inc[A]
4040

41-
type PlusLoop[A <: Tuple, B <: Tuple, O] <: Tuple = (A, B) match
41+
type PlusLoop[A <: Tuple, B <: Tuple, O <: Boolean] <: Tuple = (A, B) match
4242
case (EmptyTuple, EmptyTuple) =>
4343
O match
4444
case true => (true *: EmptyTuple)
@@ -47,4 +47,4 @@ object Sums extends App:
4747
case (A, EmptyTuple) => IncT[A, O]
4848
case (a *: as, b *: bs) =>
4949
PlusTri[a, b, O] match
50-
case (x, y) => y *: PlusLoop[as, bs, x]
50+
case (x, y) => y *: PlusLoop[as, bs, x & Boolean]

tests/pos/9239.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@ object ABug:
1010
type Zero = B0 :: Nil
1111
type One = B1 :: Nil
1212

13-
type --[B <: Bin] =
13+
type --[B <: Bin] <: Bin =
1414
B match
1515
case B1 :: d => B0 :: d
1616
case B0 :: B1 :: Nil => B1 :: Nil
1717
case B0 :: d => B1 :: --[d]
1818

19-
type ×[N <: Bin, M <: Bin] =
19+
type ×[N <: Bin, M <: Bin] <: Bin =
2020
(N, M) match
2121
case (Zero, ?) => Zero
2222

23-
type ![N <: Bin] =
23+
type ![N <: Bin] <: Bin =
2424
N match
2525
case Zero => One
2626
case One => One

tests/pos/9890.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object Test {
1010

1111
type TupleMap[Tup <: Tuple, Bound, F[_ <: Bound]] <: Tuple = Tup match {
1212
case EmptyTuple => EmptyTuple
13-
case h *: t => F[h] *: TupleMap[t, Bound, F]
13+
case h *: t => F[h & Bound] *: TupleMap[t, Bound, F]
1414
}
1515
type TupleDedup[Tup <: Tuple, Mask] <: Tuple = Tup match {
1616
case EmptyTuple => EmptyTuple

tests/pos/Tuple.FlatMap.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
type FlatMap[Tup <: Tuple, F[_] <: Tuple] <: Tuple = Tup match
2+
case EmptyTuple => EmptyTuple
3+
case h *: t => Tuple.Concat[F[h], FlatMap[t, F]]

tests/pos/Tuple.Map.scala

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
type Fold0[Tup <: Tuple, Z, F[_, _]] = Tup match
2+
case EmptyTuple => Z
3+
case h *: t => F[h, Fold0[t, Z, F]]
4+
5+
6+
type Union0[T <: Tuple] = Fold0[T, Nothing, [x, y] =>> x | y]
7+
8+
type Union1[Tup <: Tuple] = Tup match
9+
case EmptyTuple => Nothing
10+
case h *: t => h | Union1[t]
11+
12+
13+
import Tuple.Map as Map0
14+
15+
type Map1[Tup <: Tuple, F[_ <: Union0[Tup]]] <: Tuple = Tup match
16+
case EmptyTuple => EmptyTuple
17+
case h *: t => F[h & Union0[Tup]] *: Map1[t, [x <: Union0[t]] =>> F[x & Union0[Tup]]]
18+
19+
type Map2[Tup <: Tuple, F[_]] <: Tuple = Tup match
20+
case EmptyTuple => EmptyTuple
21+
case h *: t => F[h] *: Map2[t, F]
22+
23+
//type Map3[Tup <: Tuple, F[_ <: Union1[Tup]]] <: Tuple = Tup match
24+
// case EmptyTuple => EmptyTuple
25+
// case h *: t => F[h] *: Map3[t, F]
26+
27+
type Map4 [Tup <: Tuple, F[_ <: Union1[Tup]]] = Map4UB[Tup, F, Union1[Tup]]
28+
type Map4UB[Tup <: Tuple, F[_ <: UB], UB] <: Tuple = Tup match
29+
case EmptyTuple => EmptyTuple
30+
case h *: t => F[h & UB] *: Map4UB[t, F, UB]
31+
32+
type Map5 [Tup <: Tuple, F[_ <: Union1[Tup]]] = Map5UB[Tup, Union1[Tup], F, Tup]
33+
type Map5UB[Tup <: Tuple, UB, F[_ <: UB], Tup1 <: Tuple] <: Tuple = Tup1 match
34+
case EmptyTuple => EmptyTuple
35+
case h *: t => F[h & UB] *: Map5UB[Tup, UB, F, t]
36+
37+
trait Dt[T]
38+
case class IBox[A <: Int](v: A)
39+
40+
class Test[H, T <: Tuple]:
41+
//def t0 = { val x: Dt[H] *: Map0[T, Dt] = ???; val y: Map0[H *: T, Dt] = x }
42+
def t1 = { val x: Dt[H] *: Map1[T, Dt] = ???; val y: Map1[H *: T, Dt] = x }
43+
def t2 = { val x: Dt[H] *: Map2[T, Dt] = ???; val y: Map2[H *: T, Dt] = x }
44+
//def t3 = { val x: Dt[H] *: Map3[T, Dt] = ???; val y: Map3[H *: T, Dt] = x }
45+
//def t4 = { val x: Dt[H] *: Map4[T, Dt] = ???; val y: Map4[H *: T, Dt] = x }
46+
//def t5 = { val x: Dt[H] *: Map5[T, Dt] = ???; val y: Map5[H *: T, Dt] = x }
47+
48+
def i0 = { val x: Map0[(1, 2), IBox] = (IBox(1), IBox(2)) }
49+
def i1 = { val x: Map1[(1, 2), IBox] = (IBox(1), IBox(2)) }
50+
//def i2 = { val x: Map2[(1, 2), IBox] = (IBox(1), IBox(2)) }
51+
//def i3 = { val x: Map3[(1, 2), IBox] = (IBox(1), IBox(2)) }
52+
def i4 = { val x: Map4[(1, 2), IBox] = (IBox(1), IBox(2)) }
53+
def i5 = { val x: Map5[(1, 2), IBox] = (IBox(1), IBox(2)) }

tests/pos/i15926.extract.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@ final case class Succ[+N <: Nat]() extends Nat
77

88
final case class Neg[+N <: Succ[Nat]]()
99

10-
type Sum[X, Y] = Y match
10+
type Sum[X <: Nat, Y] = Y match
1111
case Zero => X
1212
case Succ[y] => Sum[Succ[X], y]
1313

1414
type IntSum[A, B] = B match
1515
case Neg[b] => IntSumNeg[A, b]
1616

1717
type IntSumNeg[A, B] = A match
18-
case Neg[a] => Neg[Sum[a, B]]
18+
case Neg[a] => Negate[Sum[a, B]]
19+
20+
type Negate[A] = A match
21+
case Zero => Zero
22+
case Succ[x] => Neg[A & Succ[x]]
1923

2024
type One = Succ[Zero]
2125
type Two = Succ[One]

tests/pos/i15926.min.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ final case class Succ[+N <: Nat]() extends Nat
77

88
final case class Neg[+N <: Succ[Nat]]()
99

10-
type Sum[X, Y] = Y match
10+
type Sum[X <: Nat, Y] <: Nat = Y match
1111
case Zero => X
1212
case Succ[y] => Sum[Succ[X], y]
1313

1414
type IntSum[A, B] = B match
1515
case Neg[b] => A match
16-
case Neg[a] => Neg[Sum[a, b]]
16+
case Neg[a] => Negate[Sum[a, b]]
17+
18+
type Negate[A] = A match
19+
case Zero => Zero
20+
case Succ[x] => Neg[A & Succ[x]]
1721

1822
type One = Succ[Zero]
1923
type Two = Succ[One]

tests/pos/i15926.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@ type NatSum[X <: NatT, Y <: NatT] <: NatT = Y match
1515
type NatDif[X <: NatT, Y <: NatT] <: IntT = Y match
1616
case Zero => X
1717
case Succ[y] => X match
18-
case Zero => Minus[Y]
18+
case Zero => Minus[Y & Succ[y]]
1919
case Succ[x] => NatDif[x, y]
2020

2121
type Sum[X <: IntT, Y <: IntT] <: IntT = Y match
2222
case Zero => X
2323
case Minus[y] => X match
24-
case Minus[x] => Minus[NatSum[x, y]]
25-
case _ => NatDif[X, y]
24+
case Minus[x] => Negate[NatSum[x, y]]
25+
case _ => NatDif[X & NatT, y]
2626
case _ => X match
27-
case Minus[x] => NatDif[Y, x]
28-
case _ => NatSum[X, Y]
27+
case Minus[x] => NatDif[Y & NatT, x]
28+
case _ => NatSum[X & NatT, Y & NatT]
29+
30+
type Negate[A] <: IntT = A match
31+
case Zero => Zero
32+
case Succ[x] => Minus[A & Succ[x]]

tests/pos/i16596.orig.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import scala.compiletime.ops.int
22

3-
type Count0[N,T] <: Tuple = (N,T) match
3+
type Count0[N <: Int,T] <: Tuple = (N,T) match
44
case (0,_) => EmptyTuple
55
case (N,String) => String *: Count0[int.-[N, 1], String]
66
case (N,Int) => Int *: Count0[int.-[N, 1], Int]
77
case (N,Float) => Float *: Count0[int.-[N, 1], Float]
88
case (N,Double) => Double *: Count0[int.-[N, 1], Double]
99

1010

11-
type Count1[N,T] <: Tuple = (N,T) match
11+
type Count1[N <: Int,T] <: Tuple = (N,T) match
1212
case (0,T) => EmptyTuple
1313
case (N,String) => String *: Count1[int.-[N, 1], String]
1414
case (N,Int) => Int *: Count1[int.-[N, 1], Int]

tests/pos/i16596.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.compiletime.ops.int, int.-
22

3-
type Count[N, T] <: Tuple = (N, T) match
3+
type Count[N <: Int, T] <: Tuple = (N, T) match
44
case (0, T) => EmptyTuple
55
case (N, T) => T *: Count[N - 1, T]
66

tests/pos/i16706.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import scala.deriving.Mirror
22
import scala.reflect.ClassTag
33

44
type TupleUnionLub[T <: Tuple, Lub, Acc <: Lub] <: Lub = T match {
5-
case (h & Lub) *: t => TupleUnionLub[t, Lub, Acc | h]
5+
case (h & Lub) *: t => TupleUnionLub[t, Lub, (Acc | h) & Lub]
66
case EmptyTuple => Acc
77
}
88

@@ -14,4 +14,4 @@ transparent inline given derived[A](
1414
sealed trait Foo
1515
case class FooA(a: Int) extends Foo
1616

17-
val instance = derived[Foo] // error
17+
val instance = derived[Foo] // error

tests/pos/singleton-ops-dispatch.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import scala.compiletime.ops.*
22

33
object Test {
44
infix type +[X <: Int | String, Y <: Int | String] = (X, Y) match {
5-
case (Int, Int) => int.+[X, Y]
6-
case (String, String) => string.+[X, Y]
7-
case (String, Int) => string.+[X, int.ToString[Y]]
8-
case (Int, String) => string.+[int.ToString[X], Y]
5+
case (Int, Int) => int.+[X & Int, Y & Int]
6+
case (String, String) => string.+[X & String, Y & String]
7+
case (String, Int) => string.+[X & String, int.ToString[Y & Int]]
8+
case (Int, String) => string.+[int.ToString[X & Int], Y & String]
99
}
1010

1111
val t0: "a" + 1 = "a1"

tests/run/i13332shapeless.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ package shapeless {
333333
def Inl[E](elem: E): E :+: Nothing = :+:(elem)
334334
def Inr[Elems <: CList](elems: Elems): Nothing :+: Elems = :+:(elems.e)
335335

336-
type CListRefl[T <: Tuple] = T match {
336+
type CListRefl[T <: Tuple] <: CList = T match {
337337
case EmptyTuple => CNil
338338
case h *: tl => h :+: CListRefl[tl]
339339
}
@@ -358,7 +358,7 @@ package shapeless {
358358

359359
object Generic:
360360

361-
type Repr[T, M, Elems] = M match
361+
type Repr[T, M, Elems <: Tuple] = M match
362362
case Mirror.Sum { type MirroredType = T } => CListRefl[Elems]
363363
case Mirror.Product { type MirroredType = T } => Elems
364364

0 commit comments

Comments
 (0)