|
1 | 1 | package org.cvogt.scala
|
2 | 2 |
|
3 |
| -import scala.reflect.macros.whitebox.Context |
4 |
| -import scala.language.dynamics |
5 | 3 | import scala.language.experimental.macros
|
| 4 | +import scala.reflect.macros.whitebox.Context |
6 | 5 |
|
7 | 6 | object Defaults {
|
8 | 7 | /** returns the given type's default values in an anonymous class instance */
|
9 |
| - def apply[T]: Any = macro DefaultsMacros.defaults[T] |
| 8 | + def apply[T]: AnyRef = macro DefaultsMacros.defaults[T] |
10 | 9 | }
|
11 | 10 |
|
12 | 11 | class DefaultsMacros( val c: Context ) {
|
13 | 12 | import c.universe._
|
14 |
| - def defaults[T: c.WeakTypeTag] = { |
| 13 | + def defaults[T: c.WeakTypeTag]: Tree = { |
15 | 14 | val T = weakTypeOf[T]
|
16 |
| - if ( !isCaseClass( T ) ) |
17 |
| - c.error( c.enclosingPosition, s"not a case class: $T" ) |
18 |
| - val defs = caseClassFieldsTypes( T ).collect { |
| 15 | + val defs = constructorFieldsTypesDefaults( T ).collect { |
19 | 16 | case ( name, tpe, Some( default ) ) => q"def ${TermName( name )}: $tpe = $default"
|
20 | 17 | }
|
21 | 18 | q"new{ ..$defs }"
|
22 | 19 | }
|
23 | 20 |
|
24 |
| - private def isCaseClass( tpe: Type ) = tpe.typeSymbol.isClass && tpe.typeSymbol.asClass.isCaseClass |
25 |
| - |
26 |
| - private def caseClassFieldsTypes( tpe: Type ): List[( String, Type, Option[Tree] )] = { |
27 |
| - tpe.companion.member( TermName( "apply" ) ).asTerm.alternatives.find( _.isSynthetic ).get.asMethod.paramLists.flatten.zipWithIndex.map { |
| 21 | + def constructorFieldsTypesDefaults( tpe: Type ): List[( String, Type, Option[Tree] )] = { |
| 22 | + val m = tpe.decls.collectFirst { |
| 23 | + case m: MethodSymbol if m.isPrimaryConstructor => m |
| 24 | + }.head.paramLists.flatten.zipWithIndex |
| 25 | + m.map { |
28 | 26 | case ( field, i ) =>
|
29 | 27 | (
|
30 | 28 | field.name.toTermName.decodedName.toString,
|
31 | 29 | field.infoIn( tpe ),
|
32 | 30 | {
|
33 |
| - val method = TermName( s"apply$$default$$${i + 1}" ) |
| 31 | + val method = TermName( "<init>$default$"+(i + 1) ).encodedName.toTermName |
34 | 32 | tpe.companion.member( method ) match {
|
35 | 33 | case NoSymbol => None
|
36 | 34 | case _ => Some( q"${tpe.typeSymbol.companion}.$method" )
|
|
0 commit comments