Skip to content

Commit 571d430

Browse files
committed
Inliner: don't confuse method parameters and nested lambda parameters
Fixes #13460
1 parent b81f50f commit 571d430

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,13 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
764764
for (param <- tpe.cls.typeParams)
765765
paramProxy(param.typeRef) = adaptToPrefix(param.typeRef)
766766
case tpe: NamedType
767-
if tpe.symbol.is(Param) && tpe.symbol.owner == inlinedMethod && !paramProxy.contains(tpe) =>
767+
if tpe.symbol.is(Param)
768+
&& tpe.symbol.owner == inlinedMethod
769+
&& (tpe.symbol.isTerm || inlinedMethod.paramSymss.exists(_.contains(tpe.symbol)))
770+
// this test is needed to rule out nested LambdaTypeTree parameters
771+
// with the same name as the method's parameters. Note that the nested
772+
// LambdaTypeTree parameters also have the inlineMethod as owner. C.f. i13460.scala.
773+
&& !paramProxy.contains(tpe) =>
768774
paramBinding.get(tpe.name) match
769775
case Some(bound) => paramProxy(tpe) = bound
770776
case _ => // can happen for params bound by type-lambda trees.
@@ -960,6 +966,11 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
960966
substTo = Nil
961967
)(using inlineCtx)
962968

969+
inlining.println(
970+
i"""inliner transform with
971+
|thisProxy = ${thisProxy.toList.map(_._1)}%, % --> ${thisProxy.toList.map(_._2)}%, %
972+
|paramProxy = ${paramProxy.toList.map(_._1.typeSymbol.showLocated)}%, % --> ${paramProxy.toList.map(_._2)}%, %""")
973+
963974
// Apply inliner to `rhsToInline`, split off any implicit bindings from result, and
964975
// make them part of `bindingsBuf`. The expansion is then the tree that remains.
965976
val expansion = inliner.transform(rhsToInline)

tests/pos/i13460.scala

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import scala.compiletime.*
2+
import scala.deriving.Mirror
3+
4+
class Lazy[A](obj: => A) {
5+
lazy val value: A = obj
6+
}
7+
object Lazy {
8+
given [A](using obj: => A ): Lazy[A] = new Lazy(obj)
9+
}
10+
11+
trait MyTypeClass[A] {
12+
def makeString(a: A): String
13+
}
14+
object MyTypeClass {
15+
16+
given IntTypeClass: MyTypeClass[Int] with
17+
def makeString(a: Int): String = a.toString
18+
19+
inline given derived[A](using m: Mirror.Of[A]): MyTypeClass[A] =
20+
inline m match
21+
case p: Mirror.ProductOf[A] => productConverter(p)
22+
23+
24+
private inline def summonElementTypeClasses[A](m: Mirror.Of[A]): IArray[Object] =
25+
// this doesn't work
26+
summonAll[Tuple.Map[m.MirroredElemTypes, [A] =>> Lazy[MyTypeClass[A]]]].toIArray
27+
// but this does
28+
// summonAll[Tuple.Map[Tuple.Map[m.MirroredElemTypes, MyTypeClass], Lazy]].toIArray
29+
30+
private inline def productConverter[A](m: Mirror.ProductOf[A]): MyTypeClass[A] = {
31+
val elementTypeClasses = summonElementTypeClasses(m)
32+
new MyTypeClass[A] {
33+
def makeString(a: A): String = {
34+
val product = a.asInstanceOf[Product]
35+
elementTypeClasses
36+
.view
37+
.zipWithIndex
38+
.map((obj, i) => {
39+
val tc = obj.asInstanceOf[Lazy[MyTypeClass[Any]]].value
40+
tc.makeString(product.productElement(i))
41+
})
42+
.mkString("[", ", ", "]")
43+
}
44+
}
45+
}
46+
}
47+
48+
case class Example(a: Int, b: Int) derives MyTypeClass
49+
50+
object Main {
51+
def main(args: Array[String]): Unit = {
52+
println("hello world")
53+
println(summon[MyTypeClass[Example]].makeString(Example(1,2)))
54+
}
55+
}

0 commit comments

Comments
 (0)