zio-mock
zio-mock copied to clipboard
Bounds on Poly input types are not represented in @mockable macro expansion
The following code does not compile on the latest 1.0.0-RC5 (and I think on any other version):
trait BoundedType[A <: AnyRef]
trait TestService {
def polyBoundedIn[A <: AnyRef: EnvironmentTag](a: BoundedType[A]): UIO[Unit]
}
and the mock :
@mockable[TestService]
object TestServiceMock
The compiler error:
<macro>:5:37: type arguments [A] do not conform to trait BoundedType's type parameter bounds [A <: AnyRef]
[error] final def polyBoundedIn[A](a: BoundedType[A])(implicit evidence$1: zio.EnvironmentTag[A]): _root_.zio.ZIO[Any, Nothing, Unit] = proxy(TestServiceMock.PolyBoundedIn.of[BoundedType[A]], a)
The problem seems to be in this part of the macro https://github.com/zio/zio-mock/blob/e437c0af392fd3b93c9e320c9d50795749bb0071/mock/shared/src/main/scala-2/zio/mock/MockableMacro.scala#L69
and in particular the bound
function:
def bound(tpe: Type): Tree =
tq"$tpe" match {
case TypeTree() => EmptyTree
case nonEmpty => nonEmpty
}
The first branch TypeTree()
matches and as a result the A <: Something
becomes just A
in the macro definition. That becomes noticeable when the parameter of the mocked method has itself a type paramater that must respect the bound, like in my example above.
I don't know macros enough to know what happens removing that "bound" function and simply always doing case TypeBounds(lo, hi) => tq"$lo" -> tq"$hi"
. I tried to modify the code and all the tests seem to pass (including a new one for the failing case), but I really don't know why that replacement with EmptyTree was there in the first place so I haven't opened a pull request for it.
If you need any more information, let me know!