diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 5870af1eb7ca..4761147a34ea 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -764,7 +764,13 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { for (param <- tpe.cls.typeParams) paramProxy(param.typeRef) = adaptToPrefix(param.typeRef) case tpe: NamedType - if tpe.symbol.is(Param) && tpe.symbol.owner == inlinedMethod && !paramProxy.contains(tpe) => + if tpe.symbol.is(Param) + && tpe.symbol.owner == inlinedMethod + && (tpe.symbol.isTerm || inlinedMethod.paramSymss.exists(_.contains(tpe.symbol))) + // this test is needed to rule out nested LambdaTypeTree parameters + // with the same name as the method's parameters. Note that the nested + // LambdaTypeTree parameters also have the inlineMethod as owner. C.f. i13460.scala. + && !paramProxy.contains(tpe) => paramBinding.get(tpe.name) match case Some(bound) => paramProxy(tpe) = bound case _ => // can happen for params bound by type-lambda trees. @@ -960,6 +966,11 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { substTo = Nil )(using inlineCtx) + inlining.println( + i"""inliner transform with + |thisProxy = ${thisProxy.toList.map(_._1)}%, % --> ${thisProxy.toList.map(_._2)}%, % + |paramProxy = ${paramProxy.toList.map(_._1.typeSymbol.showLocated)}%, % --> ${paramProxy.toList.map(_._2)}%, %""") + // Apply inliner to `rhsToInline`, split off any implicit bindings from result, and // make them part of `bindingsBuf`. The expansion is then the tree that remains. val expansion = inliner.transform(rhsToInline) diff --git a/tests/pos/i13460.scala b/tests/pos/i13460.scala new file mode 100644 index 000000000000..fd57cd9b8521 --- /dev/null +++ b/tests/pos/i13460.scala @@ -0,0 +1,55 @@ +import scala.compiletime.* +import scala.deriving.Mirror + +class Lazy[A](obj: => A) { + lazy val value: A = obj +} +object Lazy { + given [A](using obj: => A ): Lazy[A] = new Lazy(obj) +} + +trait MyTypeClass[A] { + def makeString(a: A): String +} +object MyTypeClass { + + given IntTypeClass: MyTypeClass[Int] with + def makeString(a: Int): String = a.toString + + inline given derived[A](using m: Mirror.Of[A]): MyTypeClass[A] = + inline m match + case p: Mirror.ProductOf[A] => productConverter(p) + + + private inline def summonElementTypeClasses[A](m: Mirror.Of[A]): IArray[Object] = + // this doesn't work + summonAll[Tuple.Map[m.MirroredElemTypes, [A] =>> Lazy[MyTypeClass[A]]]].toIArray + // but this does + // summonAll[Tuple.Map[Tuple.Map[m.MirroredElemTypes, MyTypeClass], Lazy]].toIArray + + private inline def productConverter[A](m: Mirror.ProductOf[A]): MyTypeClass[A] = { + val elementTypeClasses = summonElementTypeClasses(m) + new MyTypeClass[A] { + def makeString(a: A): String = { + val product = a.asInstanceOf[Product] + elementTypeClasses + .view + .zipWithIndex + .map((obj, i) => { + val tc = obj.asInstanceOf[Lazy[MyTypeClass[Any]]].value + tc.makeString(product.productElement(i)) + }) + .mkString("[", ", ", "]") + } + } + } +} + +case class Example(a: Int, b: Int) derives MyTypeClass + +object Main { + def main(args: Array[String]): Unit = { + println("hello world") + println(summon[MyTypeClass[Example]].makeString(Example(1,2))) + } +} \ No newline at end of file