Skip to content

Commit cc24375

Browse files
committed
Special-case ClassTag argument instantiation to avoid failure
The previous commit ensures that `ClassTag[Int & Nothing]` doesn't compile anymore so this isn't a soundness issue anymore, but since intersections can arise out of type inference, it's worth adding a special-case here for convenience. In particular, this fixes #16328 (comment)
1 parent 286d2a7 commit cc24375

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,21 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
2828
private type SpecialHandlers = List[(ClassSymbol, SpecialHandler)]
2929

3030
val synthesizedClassTag: SpecialHandler = (formal, span) =>
31+
def instArg(tp: Type): Type = tp.stripTypeVar match
32+
// Special case to avoid instantiating `Int & S` to `Int & Nothing` in
33+
// i16328.scala. The intersection comes from an earlier instantiation
34+
// to an upper bound.
35+
// The dual situation with unions is harder to trigger because lower
36+
// bounds are usually widened during instantiation.
37+
case tp: AndOrType if tp.tp1 =:= tp.tp2 =>
38+
instArg(tp.tp1)
39+
case _ =>
40+
if isFullyDefined(tp, ForceDegree.all) then tp
41+
else NoType // this happens in tests/neg/i15372.scala
42+
3143
val tag = formal.argInfos match
32-
case arg :: Nil if isFullyDefined(arg, ForceDegree.all) =>
33-
arg match
44+
case arg :: Nil =>
45+
instArg(arg) match
3446
case defn.ArrayOf(elemTp) =>
3547
val etag = typer.inferImplicitArg(defn.ClassTagClass.typeRef.appliedTo(elemTp), span)
3648
if etag.tpe.isError then EmptyTree else etag.select(nme.wrap)

tests/pos/i16328.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import scala.reflect.ClassTag
2+
3+
object Test {
4+
def getParamType[T: ClassTag](x: T => Int): T = ???
5+
6+
def id[S](x: S): S = x
7+
8+
def main(args: Array[String]) = {
9+
// worked before
10+
val a1 = getParamType((x: Int) => x)
11+
val a2: Int = a1 // ensure that we actually got a ClassTag for the right type
12+
13+
// broken before
14+
val b1 = id(getParamType((x: Int) => x)) // was error
15+
val b2: Int = b1
16+
val c1 = id(id(getParamType((x: Int) => x))) // was error
17+
val c2: Int = c1
18+
}
19+
}

0 commit comments

Comments
 (0)