Skip to content

Commit 66fdea9

Browse files
committed
MacroInstances no longer requires methods to be parameterless
1 parent 750e4a4 commit 66fdea9

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

commons-core/src/main/scala/com/avsystem/commons/meta/MacroInstances.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ package meta
1111
* macro-materialization of typeclasses aggregated by `Instances` trait.
1212
*
1313
* `Instances` is a trait that aggregates multiple macro materialized typeclass instances.
14-
* There is no fixed interface for `Instances`, its members are inspected by `MacroInstances.materialize`
15-
* macro and implemented automatically. `Instances` trait must have only parameterless abstract methods.
16-
* Return type of each method must have a companion object which contains `materialize` macro.
17-
* That macro will be used to implement that method.
14+
* There is no fixed interface for `Instances`, its abstract methods are inspected by
15+
* `MacroInstances.materialize` macro and implemented automatically as `<methodReturnTypeCompanion>.materialize`
16+
* Therefore, return type type of each method must have a companion object which contains `materialize` macro.
1817
*
1918
* Example of `Instances`: [[com.avsystem.commons.rest.ClientInstances ClientInstances]]
2019
*
2120
* The `Implicits` type is typically a trait with a collection of implicit definitions whose companion object
2221
* implements that trait, e.g. [[com.avsystem.commons.rest.DefaultRestImplicits DefaultRestImplicits]].
2322
* When the macro implements `apply` method of `MacroInstances` contents of `Implicits` are imported into the
2423
* body of `apply` and visible further by macros that materialize `InstancesTrait`.
24+
* If you don't want to inject additional implicits, declare `Implicits` as `Unit`.
2525
*
2626
* If `MacroInstances` is accepted as implicit super constructor parameter of a companion object
2727
* (which is the typical situation) then `this` reference should be passed as `companion`.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.avsystem.commons
2+
package meta
3+
4+
import com.avsystem.commons.serialization.GenCodec
5+
6+
case class Dep(int: Int)
7+
case class Klass[T](value: T)
8+
9+
object DependencyImplicits {
10+
implicit val depCodec: GenCodec[Dep] = GenCodec.materialize
11+
}
12+
13+
trait ComplexInstances[T] {
14+
def plainCodec: GenCodec[Klass[Int]]
15+
def codecWithGeneric: GenCodec[Klass[T]]
16+
def dependencyUsingCodec: GenCodec[Klass[Dep]]
17+
def parameterizedCodec[A: GenCodec]: GenCodec[Klass[A]]
18+
}
19+
20+
abstract class HasComplexInstances[T](
21+
implicit macroInstances: MacroInstances[DependencyImplicits.type, ComplexInstances[T]]
22+
) {
23+
val instances: ComplexInstances[T] = macroInstances(DependencyImplicits, this)
24+
}
25+
26+
object MacroInstancesTest extends HasComplexInstances[String] {
27+
def main(args: Array[String]): Unit = {
28+
println(instances.parameterizedCodec[Double])
29+
}
30+
}

commons-macros/src/main/scala/com/avsystem/commons/macros/misc/MiscMacros.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,23 +355,22 @@ class MiscMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {
355355
}
356356

357357
val instancesMethods = instancesTpe.members.iterator
358-
.filter(m => m.isAbstract && m.isMethod).toList.reverse
358+
.filter(m => m.isAbstract && m.isMethod).map(_.asMethod).toList.reverse
359359

360360
def impl(singleMethod: Option[Symbol]): Tree = {
361361
val impls = instancesMethods.map { m =>
362362
val sig = m.typeSignatureIn(instancesTpe)
363363
val resultTpe = sig.finalResultType.dealias
364-
if (sig.typeParams.nonEmpty || sig.paramLists.nonEmpty) {
365-
abort(s"Problem with $m of $instancesTpe: expected non-generic, parameterless method")
366-
}
367364
val resultCompanion = typedCompanionOf(resultTpe)
368365
.getOrElse(abort(s"$resultTpe has no companion object with `materialize` macro"))
369366

370367
val body =
371368
if (singleMethod.exists(_ != m)) q"$PredefObj.???"
372369
else q"$resultCompanion.materialize"
373370

374-
q"def ${m.name.toTermName} = $body"
371+
val tparamDefs = sig.typeParams.map(typeSymbolToTypeDef(_, forMethod = true))
372+
val paramDefs = sig.paramLists.map(_.map(paramSymbolToValDef))
373+
q"def ${m.name}[..$tparamDefs](...$paramDefs): ${treeForType(sig.finalResultType)} = $body"
375374
}
376375

377376
val implicitsName = c.freshName(TermName("implicits"))

0 commit comments

Comments
 (0)