scalazio

Why does this ZIO layer composition not compile?


Obviously, this wasn't exactly my use case, but here is the MCVE, demonstrating the problem:

  def bad = {
    val in: ZLayer[Any, Any, String] = null
    val layer: ZLayer[String with Int with Double, Any, Double] = null
    val out: ZLayer[Any & Int, Any, Double] = in >>> layer
  }

This should work, right? Intellij agrees, and says everything is right ... until you hit compile. The compiler says:

 found   : zio.ZLayer[String with Int with Double,Any,Double]
 required: zio.ZLayer[String with Any with Int,Any,Double]

What??? Why?

Interestingly, if you change the first Double to a String (or to anything else for that matter if you adjust the out type), it works fine:

  def good = {
    val in: ZLayer[Any, Any, String] = null
    val layer: ZLayer[String with Int with String, Any, Double] = null
    val out: ZLayer[Any & Int, Any, Double] = in >>> layer
  }

Any ideas? I am starting to think, this is a compiler bug?


Solution

  • Some type tetris :) Let's visualize, what's going on here:

    layer requires provides
    in - String
    layer String, Int, Double Double
    in >>> layer Int, Double Double
    out Int Double

    When you compose in and layer to in >>> layer, in eliminates String from what is required by layer, but the rest (Int and Double) is still required by the resulting layer. However, the type annotation on out in your bad example states that it only requires Int, which is not correct.

    Note that there are different ways to fix the error in bad:

    1. Add Double to what's required by out
    2. Remove Double from what's required by layer
    3. Add Double to what's provided by in

    Seems that the compiler considers the type of out fix, and suggests the second solution, which is exactly what you did in good.