Skip to content

Commit 2cf4ac3

Browse files
authored
Avoid crash arising from trying to find conversions from polymorphic singleton types (#18760)
2 parents f98a3aa + 125612f commit 2cf4ac3

File tree

4 files changed

+91
-9
lines changed

4 files changed

+91
-9
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

+6-8
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,19 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
4545
def Apply(fn: Tree, args: List[Tree])(using Context): Apply = fn match
4646
case Block(Nil, expr) =>
4747
Apply(expr, args)
48+
case _: RefTree | _: GenericApply | _: Inlined | _: Hole =>
49+
ta.assignType(untpd.Apply(fn, args), fn, args)
4850
case _ =>
49-
assert(
50-
fn.isInstanceOf[RefTree | GenericApply | Inlined | Hole] || ctx.reporter.errorsReported,
51-
s"Illegal Apply function prefix: $fn"
52-
)
51+
assert(ctx.reporter.errorsReported)
5352
ta.assignType(untpd.Apply(fn, args), fn, args)
5453

5554
def TypeApply(fn: Tree, args: List[Tree])(using Context): TypeApply = fn match
5655
case Block(Nil, expr) =>
5756
TypeApply(expr, args)
57+
case _: RefTree | _: GenericApply =>
58+
ta.assignType(untpd.TypeApply(fn, args), fn, args)
5859
case _ =>
59-
assert(
60-
fn.isInstanceOf[RefTree | GenericApply] || ctx.reporter.errorsReported,
61-
s"Illegal TypeApply function prefix: $fn"
62-
)
60+
assert(ctx.reporter.errorsReported, s"unexpected tree for type application: $fn")
6361
ta.assignType(untpd.TypeApply(fn, args), fn, args)
6462

6563
def Literal(const: Constant)(using Context): Literal =

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -4366,7 +4366,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
43664366
case _ =>
43674367
adaptOverloaded(ref)
43684368
}
4369-
case poly: PolyType if !(ctx.mode is Mode.Type) =>
4369+
case poly: PolyType
4370+
if !(ctx.mode is Mode.Type) && dummyTreeOfType.unapply(tree).isEmpty =>
4371+
// If we are in a conversion from a TermRef with polymorphic underlying
4372+
// type, give up. In this case the typed `null` literal cannot be instantiated.
4373+
// Test case was but i18695.scala, but it got fixed by a different tweak in #18719.
4374+
// We leave test for this condition in as a defensive measure in case
4375+
// it arises somewhere else.
43704376
if isApplyProxy(tree) then newExpr
43714377
else if pt.isInstanceOf[PolyProto] then tree
43724378
else

tests/neg-macros/i18695.scala

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import scala.annotation.{tailrec, unused}
2+
import scala.deriving.Mirror
3+
import scala.quoted.*
4+
5+
trait TypeLength[A] {
6+
type Length <: Int
7+
def length: Length
8+
}
9+
object TypeLength extends TypeLengthLowPriority:
10+
type Aux[A, Length0 <: Int] = TypeLength[A] {
11+
type Length = Length0
12+
}
13+
14+
transparent inline given fromMirror[A](using m: Mirror.Of[A]): TypeLength[A] =
15+
${ macroImpl[A, m.MirroredElemTypes] }
16+
17+
@tailrec
18+
private def typesOfTuple(
19+
using q: Quotes
20+
)(tpe: q.reflect.TypeRepr, acc: List[q.reflect.TypeRepr]): List[q.reflect.TypeRepr] =
21+
import q.reflect.*
22+
val cons = Symbol.classSymbol("scala.*:")
23+
tpe.widenTermRefByName.dealias match
24+
case AppliedType(fn, tpes) if defn.isTupleClass(fn.typeSymbol) =>
25+
tpes.reverse_:::(acc)
26+
case AppliedType(tp, List(headType, tailType)) if tp.derivesFrom(cons) =>
27+
typesOfTuple(tailType, headType :: acc)
28+
case tpe =>
29+
if tpe.derivesFrom(Symbol.classSymbol("scala.EmptyTuple")) then acc.reverse
30+
else report.errorAndAbort(s"Unknown type encountered in tuple ${tpe.show}")
31+
32+
def macroImpl[A: Type, T <: Tuple: scala.quoted.Type](
33+
using q: scala.quoted.Quotes
34+
): scala.quoted.Expr[TypeLength[A]] =
35+
import q.reflect.*
36+
val l = typesOfTuple(TypeRepr.of[T], Nil).length
37+
ConstantType(IntConstant(l)).asType match
38+
case '[lt] =>
39+
val le = Expr[Int](l).asExprOf[lt & Int]
40+
'{
41+
val r: TypeLength.Aux[A, lt & Int] = new TypeLength[A] {
42+
type Length = lt & Int
43+
val length: Length = ${ le }
44+
}
45+
r
46+
}
47+
48+
transparent inline given fromTuple[T <: Tuple]: TypeLength[T] =
49+
${ macroImpl[T, T] }
50+
51+
trait TypeLengthLowPriority:
52+
self: TypeLength.type =>
53+
given tupleFromMirrorAndLength[A, T <: Tuple](
54+
using @unused m: Mirror.Of[A] { type MirroredElemTypes = T },
55+
length: TypeLength[A]
56+
): TypeLength.Aux[T, length.Length] = length.asInstanceOf[TypeLength.Aux[T, length.Length]]
57+
58+
trait HKDSumGeneric[A]
59+
object HKDSumGeneric:
60+
type NotZero[N <: Int] = N match
61+
case 0 => false
62+
case _ => true
63+
64+
transparent inline given derived[A](using m: Mirror.SumOf[A], typeLength: TypeLength[A])(
65+
using NotZero[typeLength.Length] =:= true
66+
): HKDSumGeneric[A] =
67+
derivedImpl[A, m.MirroredElemTypes, m.MirroredLabel] // error
68+
69+
def derivedImpl[A, ElemTypes <: Tuple, Label <: String](
70+
using m: Mirror.SumOf[A] {
71+
type MirroredElemTypes = ElemTypes; type MirroredLabel = Label;
72+
},
73+
typeLength: TypeLength[ElemTypes],
74+
nz: NotZero[typeLength.Length] =:= true
75+
): HKDSumGeneric[A] = ???

tests/neg/i18695.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait Foo { type Num <: Int }
2+
given derived[A](using foo: Foo): Any = derivedImpl(foo) // error
3+
def derivedImpl(foo: Foo)(using bar: foo.Num =:= Int): Any = ???

0 commit comments

Comments
 (0)