Skip to content

Commit 23febb8

Browse files
authored
Fix check whether classtag can be generated for match types (#16708)
The previous check, meant to address #15618, tested whether all alternatives of a match type had the same classtag and only then permitted a classtag for the match type. This was the wrong test. It did not work for recursive match types, because it could lead to stack overflow for them. And it did not take into account that match types could be reduced. A better test is to simply declare that match types themselves don't have a stable erasure, just like TypeBounds don't have a stable erasure. If we find an applied type with a match type as definition, we proceed to its translucent supertype, which will try a match type reduction. If that succeeds we produce the classtag of the redux. If not, we end up with an unreduced matchtype and refuse to generate a classtag for it. Fixes #16706 Fixes #16707
2 parents bb2d28f + 027923c commit 23febb8

File tree

6 files changed

+46
-10
lines changed

6 files changed

+46
-10
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,8 +520,9 @@ object TypeErasure {
520520
case _: ClassInfo => true
521521
case _ => false
522522
}
523-
case tp: TypeParamRef => false
524-
case tp: TypeBounds => false
523+
case _: TypeParamRef => false
524+
case _: TypeBounds => false
525+
case _: MatchType => false
525526
case tp: TypeProxy => hasStableErasure(tp.translucentSuperType)
526527
case tp: AndType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
527528
case tp: OrType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
5252
if defn.SpecialClassTagClasses.contains(sym) then
5353
classTagModul.select(sym.name.toTermName).withSpan(span)
5454
else
55-
def clsOfType(tp: Type): Type = tp.dealias.underlyingMatchType match
56-
case matchTp: MatchType =>
57-
matchTp.alternatives.map(clsOfType) match
58-
case ct1 :: cts if cts.forall(ct1 == _) => ct1
59-
case _ => NoType
60-
case _ =>
61-
escapeJavaArray(erasure(tp))
62-
val ctype = clsOfType(tp)
55+
val ctype = escapeJavaArray(erasure(tp))
6356
if ctype.exists then
6457
classTagModul.select(nme.apply)
6558
.appliedToType(tp)

tests/neg/i15618.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@
1616
|
1717
| case Float32 => Float
1818
| case Int32 => Int
19+
-- [E172] Type Error: tests/neg/i15618.scala:21:33 ---------------------------------------------------------------------
20+
21 | def toArray: Array[T] = Array() // error
21+
| ^
22+
| No ClassTag available for T
23+
|
24+
| where: T is a type in class Tensor2 with bounds <: Int | Float

tests/neg/i15618.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,16 @@ class Tensor[T <: DType](dtype: T):
1616
def toSeq: Seq[ScalaType[T]] = Seq()
1717
def toArray: Array[ScalaType[T]] = Array() // error
1818

19+
class Tensor2[T <: Int | Float](dtype: T):
20+
def toSeq: Seq[T] = Seq()
21+
def toArray: Array[T] = Array() // error
22+
1923
@main
2024
def Test =
2125
val t = Tensor(Float32) // Tensor[Float32]
2226
println(t.toSeq.headOption) // works, Seq[Float]
2327
println(t.toArray.headOption) // ClassCastException
28+
29+
val t2 = Tensor2(0.0f) // Tensor2[Float]
30+
println(t.toSeq.headOption)
31+
println(t.toArray.headOption)

tests/pos/i16706.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.deriving.Mirror
2+
import scala.reflect.ClassTag
3+
4+
type TupleUnionLub[T <: Tuple, Lub, Acc <: Lub] <: Lub = T match {
5+
case (h & Lub) *: t => TupleUnionLub[t, Lub, Acc | h]
6+
case EmptyTuple => Acc
7+
}
8+
9+
transparent inline given derived[A](
10+
using m: Mirror.SumOf[A],
11+
idClassTag: ClassTag[TupleUnionLub[m.MirroredElemTypes, A, Nothing]]
12+
): Unit = ()
13+
14+
sealed trait Foo
15+
case class FooA(a: Int) extends Foo
16+
17+
val instance = derived[Foo] // error

tests/pos/i16707.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.deriving.Mirror
2+
import scala.reflect.ClassTag
3+
4+
transparent inline given derived[A](
5+
using m: Mirror.ProductOf[A],
6+
idClassTag: ClassTag[Tuple.Union[m.MirroredElemTypes]]
7+
): Unit = ???
8+
9+
case class Foo(a: Int)
10+
11+
val instance = derived[Foo] // error

0 commit comments

Comments
 (0)