Closed
Description
Compiler version
3.3.1
Minimized code
This is a slightly changed code from https://github.com/lampepfl/dotty-macro-examples/tree/main/defaultParamsInference, two files as in the example:
macro.scala:
package dummy
import scala.quoted.*
trait Defaults[A]:
def defaults: Map[String, Any]
object Defaults:
inline def derived[A <: Product]: Defaults[A] = ${ defaultsImpl[A] }
def defaultsImpl[A <: Product: Type](using Quotes): Expr[Defaults[A]] =
'{
new Defaults[A]:
def defaults: Map[String, Any] = ${ defaultParmasImpl[A] }
}
inline def defaultParams[T]: Map[String, Any] = ${ defaultParmasImpl[T] }
def defaultParmasImpl[T](using quotes: Quotes, tpe: Type[T]): Expr[Map[String, Any]] =
import quotes.reflect.*
TypeRepr.of[T].classSymbol match
case None => '{ Map.empty[String, Any] }
case Some(sym) =>
val comp = sym.companionClass
val mod = Ref(sym.companionModule)
val names =
for p <- sym.caseFields if p.flags.is(Flags.HasDefault)
yield p.name
val namesExpr: Expr[List[String]] =
Expr.ofList(names.map(Expr(_)))
val body = comp.tree.asInstanceOf[ClassDef].body
val idents: List[Ref] =
for
case deff @ DefDef(name, _, _, _) <- body
if name.startsWith("$lessinit$greater$default")
yield mod.select(deff.symbol)
val typeArgs = TypeRepr.of[T].typeArgs
val identsExpr: Expr[List[Any]] =
if typeArgs.isEmpty then Expr.ofList(idents.map(_.asExpr))
else Expr.ofList(idents.map(_.appliedToTypes(typeArgs).asExpr))
'{ $namesExpr.zip($identsExpr).toMap }
dummy.scala:
package dummy
case class Person(name: String, address: String = "Zuricch", foo: Int, age: Int = 26)
case class Test3[A, B](as: List[A], bs: List[B] = List.empty)
object Person:
val x = 10
class Outer:
case class Inner(a: String, b: Int = 23) derives Defaults
@main def test(): Unit =
val p1 = Person("John", foo = 10)
val t1 = Test3(List("string"), List(23.0))
println(p1)
println(t1)
println(defaultParams[Person])
println(defaultParams[Test3[String, Double]])
assert(defaultParams[Person] == Map("address" -> "Zuricch", "age" -> 26))
val outer = Outer()
println(summon[Defaults[outer.Inner]].defaults)
How to run:
- place both files in an empty directory
- run
scala-cli run . -S 3.3.1 --server=false
For some reason this does not happen when using the defaultParams
macro directly but does happen if the same macro is executed via macro called by derives
. Only happens for inner classes, other cases seem to work fine.
Output (click arrow to expand)
-- Error: /Users/lbialy/Projects/foss/tmp/macros/dummy.scala:10:51 -------------
10 | case class Inner(a: String, b: Int = 23) derives Defaults
| ^
|Exception occurred while executing macro expansion.
|java.lang.ClassCastException: class dotty.tools.dotc.ast.Trees$This cannot be cast to class dotty.tools.dotc.ast.Trees$RefTree (dotty.tools.dotc.ast.Trees$This and dotty.tools.dotc.ast.Trees$RefTree are in unnamed module of loader 'app')
| at scala.quoted.runtime.impl.QuotesImpl.scala$quoted$runtime$impl$QuotesImpl$reflect$Ref$$$_$apply$$anonfun$6(QuotesImpl.scala:445)
| at scala.quoted.runtime.impl.QuotesImpl$reflect$.scala$quoted$runtime$impl$QuotesImpl$reflect$$$withDefaultPos(QuotesImpl.scala:2997)
| at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:445)
| at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:443)
| at dummy.macro$package$.defaultParmasImpl(macro.scala:25)
| at dummy.Defaults$.defaultsImpl$$anonfun$1(macro.scala:14)
| at dummy.Defaults$.defaultsImpl$$anonfun$adapted$1(macro.scala:14)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:110)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1538)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1570)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$1(Trees.scala:1605)
| at scala.collection.immutable.List.mapConserve(List.scala:472)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1605)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transformStats(Trees.scala:1601)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1574)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1572)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$1(Trees.scala:1605)
| at scala.collection.immutable.List.mapConserve(List.scala:472)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1605)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transformStats(Trees.scala:1601)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transformBlock(Trees.scala:1603)
| at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1518)
| at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
| at dotty.tools.dotc.quoted.PickledQuotes$.spliceTerms(PickledQuotes.scala:152)
| at dotty.tools.dotc.quoted.PickledQuotes$.unpickleTerm(PickledQuotes.scala:88)
| at scala.quoted.runtime.impl.QuotesImpl.unpickleExprV2(QuotesImpl.scala:3143)
| at dummy.Defaults$.defaultsImpl(macro.scala:14)
|
|----------------------------------------------------------------------------
|Inline stack trace
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|This location contains code that was inlined from macro.scala:9
9 | inline def derived[A <: Product]: Defaults[A] = ${ defaultsImpl[A] }
| ^^^^^^^^^^^^^^^^^^^^
----------------------------------------------------------------------------
1 error found
Compilation failed