Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression: Unrepresentable invalid type inferred in implicit search with a HKT type lambda using a library type and ignoring some of its arguments, when variance is used on HKT parameters #15888

Open
neko-kai opened this issue Aug 19, 2022 · 2 comments

Comments

@neko-kai
Copy link
Contributor

neko-kai commented Aug 19, 2022

Compiler version

3.1.3

Minimized code

Scastie: https://scastie.scala-lang.org/pz6QIrsKQqe6qrdZDeSLvg

Using -Ykind-projector

object x {
  sealed trait ZIO[-R, +E, +A] extends ZIOVersionSpecific[R, E, A]
  // this trait is required for the error to surface
  trait ZIOVersionSpecific[-R, +E, +A]

  type IO[+E, +A] = ZIO[Any, E, A]
}

object example {

  import x.{IO, ZIO}

  trait Panic3[F[-_, +_, +_]] extends Root

  type Panic2[F[+_, +_]] = Panic3[λ[(`-R`, `+E`, `+A`) => F[E, A]]]

  trait Root
  object Root extends RootInstancesLowPriority7

  sealed trait RootInstancesLowPriority7 extends RootInstancesLowPriority12 {
    @inline implicit final def BIOZIO: Panic3[ZIO] = null
  }

  sealed trait RootInstancesLowPriority12 {
    @inline implicit final def Convert3To2[C[f[-_, +_, +_]] <: Root, FR[-_, +_, +_], R0](
      implicit BifunctorPlus: Root & C[FR] // `Root &` required due to https://github.com/lampepfl/dotty/issues/13986
    ): C[λ[(`-R`, `+E`, `+A`) => FR[R0, E, A]]] = {
      BifunctorPlus.asInstanceOf[C[λ[(`-R`, `+E`, `+A`) => FR[R0, E, A]]]]
    }
  }

  trait FreeMonad[F[+_, +_], +E, +A] {
    @inline def foldMap[G[+_, +_], E, A](fg: Interpreter[F, G])(implicit G: Panic2[G]): G[E, A] = null.asInstanceOf[G[E, A]]
  }

  // NOTE: variance on Interpreter parameters is required for the error, removing variance makes it disappear
  // type Interpreter[Source[+_, +_], Target[+_, +_]]
  type Interpreter[-Source[+_, +_], +Target[+_, +_]]

  sealed trait TestFreeChoice[+E, +A]

  @main def main: Unit = {
    println(
      implicitly[Panic2[IO]]
    )
    println(
      implicitly[Panic2[λ[(`+E`, `+A`) => ZIO[Any, E, A]]]]
    )

    val interpreter: Interpreter[TestFreeChoice, IO] = null.asInstanceOf[Interpreter[TestFreeChoice, IO]]
    val value: FreeMonad[TestFreeChoice, Nothing, Unit] = new FreeMonad[TestFreeChoice, Nothing, Unit] {}
    println(value.foldMap(interpreter))
  }

}

Output

no given instance of type example.Panic2[([E, A] =>> zio.ZIO[Any, E, A])] was found for parameter G of method foldMap in trait FreeMonad.
I found:

    example.Root.Convert3To2[C, FR, R0]

But method Convert3To2 in trait RootInstancesLowPriority12 does not match type example.Panic2[([E, A] =>> zio.ZIO[Any, E, A])].

However, searching for the implicit with the quoted type immediately works: implicitly[example.Panic2[([E, A] =>> zio.ZIO[Any, E, A])]], as does giving explicit type argument to foldMap

The bug only surfaces with inference with 2 specific conditions: Variance annotations on Interpreter and type x.ZIO must inherit another trait trait ZIOVersionSpecific[-R, +E, +A]

Expectation

Expected to work, as in Scala 2 https://scastie.scala-lang.org/jdr2LjLzT3e9eaztflgzSQ

This code is a minimized version of real library code in https://github.com/izumi/izumi which we're trying to port to Scala 3

@neko-kai neko-kai added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Aug 19, 2022
@soronpo
Copy link
Contributor

soronpo commented Aug 20, 2022

(Bug is not reproducible when a ZIO-like type is defined inline, for some reason)

Did you try to create a separate file that defined the ZIO types and run the build separately? It could be an issue of incremental compilation, but it needs to be minimized without the library dependency.

@szymon-rd szymon-rd added stat:needs minimization Needs a self contained minimization area:typer area:incremental-compilation area:implicits related to implicits and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Aug 22, 2022
@neko-kai
Copy link
Contributor Author

neko-kai commented Aug 22, 2022

@soronpo
I managed to minimize it without a library dependency or a separate file – just need to add a parent trait to ZIO - trait ZIOVersionSpecific[-R, +E, +A].

I've updated the code and links in the initial message too.

object x {
  sealed trait ZIO[-R, +E, +A] extends ZIOVersionSpecific[R, E, A]
  // this trait is required for the error to surface
  trait ZIOVersionSpecific[-R, +E, +A]

  type IO[+E, +A] = ZIO[Any, E, A]
}

object example {

  import x.{IO, ZIO}

  trait Panic3[F[-_, +_, +_]] extends Root

  type Panic2[F[+_, +_]] = Panic3[λ[(`-R`, `+E`, `+A`) => F[E, A]]]

  trait Root
  object Root extends RootInstancesLowPriority7

  sealed trait RootInstancesLowPriority7 extends RootInstancesLowPriority12 {
    @inline implicit final def BIOZIO: Panic3[ZIO] = null
  }

  sealed trait RootInstancesLowPriority12 {
    @inline implicit final def Convert3To2[C[f[-_, +_, +_]] <: Root, FR[-_, +_, +_], R0](
      implicit BifunctorPlus: Root & C[FR] // `Root &` required due to https://github.com/lampepfl/dotty/issues/13986
    ): C[λ[(`-R`, `+E`, `+A`) => FR[R0, E, A]]] = {
      BifunctorPlus.asInstanceOf[C[λ[(`-R`, `+E`, `+A`) => FR[R0, E, A]]]]
    }
  }

  trait FreeMonad[F[+_, +_], +E, +A] {
    @inline def foldMap[G[+_, +_], E, A](fg: Interpreter[F, G])(implicit G: Panic2[G]): G[E, A] = null.asInstanceOf[G[E, A]]
  }

  // NOTE: variance on Interpreter parameters is required for the error, removing variance makes it disappear
  // type Interpreter[Source[+_, +_], Target[+_, +_]]
  type Interpreter[-Source[+_, +_], +Target[+_, +_]]

  sealed trait TestFreeChoice[+E, +A]

  @main def main: Unit = {
    println(
      implicitly[Panic2[IO]]
    )
    println(
      implicitly[Panic2[λ[(`+E`, `+A`) => ZIO[Any, E, A]]]]
    )

    val interpreter: Interpreter[TestFreeChoice, IO] = null.asInstanceOf[Interpreter[TestFreeChoice, IO]]
    val value: FreeMonad[TestFreeChoice, Nothing, Unit] = new FreeMonad[TestFreeChoice, Nothing, Unit] {}
    println(value.foldMap(interpreter))
  }

}

@soronpo soronpo removed the stat:needs minimization Needs a self contained minimization label Aug 22, 2022
@Kordyjan Kordyjan added this to the Future versions milestone Dec 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants