Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Compiler crash when using implicit class and NotGiven and cats #24187

Copy link
Copy link
@jdrphillips

Description

@jdrphillips
Issue body actions

Compiler version

3.6.3, 3.7.2

Minimized code

Dependencies: cats:2.13.0, cats-effect:3.6.3

Apologies but the bug seems tied to something cats is doing with Apply which I am unable to minimise.

Scastie link

import scala.util.NotGiven
import cats.data.*
import cats.effect.*
import cats.syntax.apply.*

object Testing {

  val unit: EitherT[IO, Exception, Unit] = ???

  implicit class EitherTOps[T](io: IO[T]) {
    def asEitherT(using NotGiven[T <:< Either[?, ?]]): EitherT[IO, Exception, T] = ???
  }

  unit *> IO(Right(5)).asEitherT
                       // ^ this call is the broken bit
}

Notes:

  • It only breaks if the NotGiven is not satisfied
  • It breaks for any unsatisfied NotGiven condition
  • It requires a NotGiven clause, a "normal" unsatisfied implicit fails as expected
  • It works fine with extension rather than implicit class
  • It works fine with .flatMap(_ =>...) instead of *>
  • It seems to break with any monad transformer from cats
  • It works fine with a "simple" type like IO, seems to only fail on monad-transformer-like types

Output (click arrow to expand)

error when pickling type T error when pickling tree T of class class dotty.tools.dotc.ast.Trees$InferredTypeTree error when pickling tree cats.syntax.apply.catsSyntaxApplyOps[ [T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit]( Playground.Testing.Foo.unit).*>[T] of class class dotty.tools.dotc.ast.Trees$TypeApply error when pickling tree cats.syntax.apply.catsSyntaxApplyOps[ [T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit]( Playground.Testing.Foo.unit).*>[T]( Playground.Testing.EitherTOps[T]( cats.effect.IO.apply[Right[Nothing, Int]](Right.apply[Nothing, Int](5))). asFoo(scala.util.NotGiven.value) ) of class class dotty.tools.dotc.ast.Trees$Apply error when pickling tree cats.syntax.apply.catsSyntaxApplyOps[ [T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit]( Playground.Testing.Foo.unit).*>[T]( Playground.Testing.EitherTOps[T]( cats.effect.IO.apply[Right[Nothing, Int]](Right.apply[Nothing, Int](5))). asFoo(scala.util.NotGiven.value) )( cats.data.EitherT.catsDataMonadErrorForEitherT[cats.effect.IO, Exception]( cats.effect.IO.asyncForIO) ) of class class dotty.tools.dotc.ast.Trees$Apply error when pickling tree () extends Object() { this: Playground.Testing.type => private def writeReplace(): AnyRef = new scala.runtime.ModuleSerializationProxy(classOf[Playground.Testing.type]) type Foo[T >: Nothing <: Any] = cats.data.EitherT[IO, Exception, T] final lazy module val Foo: Playground.Testing.Foo = new Playground.Testing.Foo() final module class Foo() extends Object() { this: Playground.Testing.Foo.type => private def writeReplace(): AnyRef = new scala.runtime.ModuleSerializationProxy( classOf[Playground.Testing.Foo.type]) def unit: Playground.Testing.Foo[Unit] = ??? } implicit class EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T]) extends Object() { T private[this] val io: cats.effect.IO[T] def asFoo(using x$1: scala.util.NotGiven[ <:<[EitherTOps.this.T, Either[? >: Nothing <: Any, ? >: Nothing <: Any]] ] ): Playground.Testing.Foo[EitherTOps.this.T] = ??? } final implicit def EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T]): Playground.Testing.EitherTOps[T] = new Playground.Testing.EitherTOps[T](io) cats.syntax.apply.catsSyntaxApplyOps[ [T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit]( Playground.Testing.Foo.unit).*>[T]( Playground.Testing.EitherTOps[T]( cats.effect.IO.apply[Right[Nothing, Int]](Right.apply[Nothing, Int](5))). asFoo(scala.util.NotGiven.value) )( cats.data.EitherT.catsDataMonadErrorForEitherT[cats.effect.IO, Exception]( cats.effect.IO.asyncForIO) ) } of class class dotty.tools.dotc.ast.Trees$Template error when pickling tree final module class Testing() extends Object() { this: Playground.Testing.type => private def writeReplace(): AnyRef = new scala.runtime.ModuleSerializationProxy(classOf[Playground.Testing.type]) type Foo[T >: Nothing <: Any] = cats.data.EitherT[IO, Exception, T] final lazy module val Foo: Playground.Testing.Foo = new Playground.Testing.Foo() final module class Foo() extends Object() { this: Playground.Testing.Foo.type => private def writeReplace(): AnyRef = new scala.runtime.ModuleSerializationProxy( classOf[Playground.Testing.Foo.type]) def unit: Playground.Testing.Foo[Unit] = ??? } implicit class EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T]) extends Object() { T private[this] val io: cats.effect.IO[T] def asFoo(using x$1: scala.util.NotGiven[ <:<[EitherTOps.this.T, Either[? >: Nothing <: Any, ? >: Nothing <: Any]] ] ): Playground.Testing.Foo[EitherTOps.this.T] = ??? } final implicit def EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T]): Playground.Testing.EitherTOps[T] = new Playground.Testing.EitherTOps[T](io) cats.syntax.apply.catsSyntaxApplyOps[ [T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit]( Playground.Testing.Foo.unit).*>[T]( Playground.Testing.EitherTOps[T]( cats.effect.IO.apply[Right[Nothing, Int]](Right.apply[Nothing, Int](5))). asFoo(scala.util.NotGiven.value) )( cats.data.EitherT.catsDataMonadErrorForEitherT[cats.effect.IO, Exception]( cats.effect.IO.asyncForIO) ) } of class class dotty.tools.dotc.ast.Trees$TypeDef error when pickling tree () extends Object(), com.olegych.scastie.api.runtime.ScastieApp { this: Playground.type => private def writeReplace(): AnyRef = new scala.runtime.ModuleSerializationProxy(classOf[Playground.type]) private[this] val instrumentationMap:
  scala.collection.mutable.Map[com.olegych.scastie.api.Position,
    com.olegych.scastie.api.Render]

=
root.scala.collection.mutable.Map.empty[
root.com.olegych.scastie.api.Position,
root.com.olegych.scastie.api.Render]
def instrumentations: List[com.olegych.scastie.api.Instrumentation] =
Playground.instrumentationMap.toList.map[
com.olegych.scastie.api.Instrumentation]((
x$1: (com.olegych.scastie.api.Position, com.olegych.scastie.api.Render))
=>
x$1 match
{
case
Tuple2.unapply[com.olegych.scastie.api.Position,
com.olegych.scastie.api.Render](pos @ _, r @ _)
=>
root.com.olegych.scastie.api.Instrumentation.apply(pos, r)
}
)
import scala.util.NotGiven
import cats.data.*
import cats.effect.*
import cats.syntax.package.apply.*
final lazy module val Testing: Playground.Testing = new Playground.Testing()
final module class Testing() extends Object() {
this: Playground.Testing.type =>
private def writeReplace(): AnyRef =
new scala.runtime.ModuleSerializationProxy(
classOf[Playground.Testing.type])
type Foo[T >: Nothing <: Any] = cats.data.EitherT[IO, Exception, T]
final lazy module val Foo: Playground.Testing.Foo =
new Playground.Testing.Foo()
final module class Foo() extends Object() {
this: Playground.Testing.Foo.type =>
private def writeReplace(): AnyRef =
new scala.runtime.ModuleSerializationProxy(
classOf[Playground.Testing.Foo.type])
def unit: Playground.Testing.Foo[Unit] = ???
}
implicit class EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T])
extends Object() {
T
private[this] val io: cats.effect.IO[T]
def asFoo(using
x$1:
scala.util.NotGiven[
<:<[EitherTOps.this.T,
Either[? >: Nothing <: Any, ? >: Nothing <: Any]]
]
): Playground.Testing.Foo[EitherTOps.this.T] = ???
}
final implicit def EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T]):
Playground.Testing.EitherTOps[T] =
new Playground.Testing.EitherTOpsT
cats.syntax.apply.catsSyntaxApplyOps
[T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit
.*>[T](
Playground.Testing.EitherTOps[T](
cats.effect.IO.apply[Right[Nothing, Int]](Right.applyNothing, Int))
.asFoo(scala.util.NotGiven.value)
)(
cats.data.EitherT.catsDataMonadErrorForEitherTcats.effect.IO, Exception
)
}
} of class class dotty.tools.dotc.ast.Trees$Template
error when pickling tree @sourcefile("src/main/scala/main.scala") final module class Playground() extends
Object(), com.olegych.scastie.api.runtime.ScastieApp {
this: Playground.type =>
private def writeReplace(): AnyRef =
new scala.runtime.ModuleSerializationProxy(classOf[Playground.type])
private[this] val instrumentationMap:

  scala.collection.mutable.Map[com.olegych.scastie.api.Position,
    com.olegych.scastie.api.Render]

=
root.scala.collection.mutable.Map.empty[
root.com.olegych.scastie.api.Position,
root.com.olegych.scastie.api.Render]
def instrumentations: List[com.olegych.scastie.api.Instrumentation] =
Playground.instrumentationMap.toList.map[
com.olegych.scastie.api.Instrumentation]((
x$1: (com.olegych.scastie.api.Position, com.olegych.scastie.api.Render))
=>
x$1 match
{
case
Tuple2.unapply[com.olegych.scastie.api.Position,
com.olegych.scastie.api.Render](pos @ _, r @ _)
=>
root.com.olegych.scastie.api.Instrumentation.apply(pos, r)
}
)
import scala.util.NotGiven
import cats.data.*
import cats.effect.*
import cats.syntax.package.apply.*
final lazy module val Testing: Playground.Testing = new Playground.Testing()
final module class Testing() extends Object() {
this: Playground.Testing.type =>
private def writeReplace(): AnyRef =
new scala.runtime.ModuleSerializationProxy(
classOf[Playground.Testing.type])
type Foo[T >: Nothing <: Any] = cats.data.EitherT[IO, Exception, T]
final lazy module val Foo: Playground.Testing.Foo =
new Playground.Testing.Foo()
final module class Foo() extends Object() {
this: Playground.Testing.Foo.type =>
private def writeReplace(): AnyRef =
new scala.runtime.ModuleSerializationProxy(
classOf[Playground.Testing.Foo.type])
def unit: Playground.Testing.Foo[Unit] = ???
}
implicit class EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T])
extends Object() {
T
private[this] val io: cats.effect.IO[T]
def asFoo(using
x$1:
scala.util.NotGiven[
<:<[EitherTOps.this.T,
Either[? >: Nothing <: Any, ? >: Nothing <: Any]]
]
): Playground.Testing.Foo[EitherTOps.this.T] = ???
}
final implicit def EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T]):
Playground.Testing.EitherTOps[T] =
new Playground.Testing.EitherTOpsT
cats.syntax.apply.catsSyntaxApplyOps
[T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit
.>[T](
Playground.Testing.EitherTOps[T](
cats.effect.IO.apply[Right[Nothing, Int]](Right.applyNothing, Int))
.asFoo(scala.util.NotGiven.value)
)(
cats.data.EitherT.catsDataMonadErrorForEitherTcats.effect.IO, Exception
)
}
} of class class dotty.tools.dotc.ast.Trees$TypeDef
error when pickling tree package {
import root.com.olegych.scastie.api.runtime.

final lazy module val Playground: Playground = new Playground()
@sourcefile("src/main/scala/main.scala") final module class Playground()
extends Object(), com.olegych.scastie.api.runtime.ScastieApp {
this: Playground.type =>
private def writeReplace(): AnyRef =
new scala.runtime.ModuleSerializationProxy(classOf[Playground.type])
private[this] val instrumentationMap:

    scala.collection.mutable.Map[com.olegych.scastie.api.Position,
      com.olegych.scastie.api.Render]
  
 =
  _root_.scala.collection.mutable.Map.empty[
    _root_.com.olegych.scastie.api.Position,
    _root_.com.olegych.scastie.api.Render]
def instrumentations: List[com.olegych.scastie.api.Instrumentation] =
  Playground.instrumentationMap.toList.map[
    com.olegych.scastie.api.Instrumentation]((
    x$1: (com.olegych.scastie.api.Position, com.olegych.scastie.api.Render))
     =>
    x$1 match 
      {
        case 
          Tuple2.unapply[com.olegych.scastie.api.Position,
            com.olegych.scastie.api.Render](pos @ _, r @ _)
         =>
          _root_.com.olegych.scastie.api.Instrumentation.apply(pos, r)
      }
  )
import scala.util.NotGiven
import cats.data.*
import cats.effect.*
import cats.syntax.package.apply.*
final lazy module val Testing: Playground.Testing = new Playground.Testing()
final module class Testing() extends Object() {
  this: Playground.Testing.type =>
  private def writeReplace(): AnyRef =
    new scala.runtime.ModuleSerializationProxy(
      classOf[Playground.Testing.type])
  type Foo[T >: Nothing <: Any] = cats.data.EitherT[IO, Exception, T]
  final lazy module val Foo: Playground.Testing.Foo =
    new Playground.Testing.Foo()
  final module class Foo() extends Object() {
    this: Playground.Testing.Foo.type =>
    private def writeReplace(): AnyRef =
      new scala.runtime.ModuleSerializationProxy(
        classOf[Playground.Testing.Foo.type])
    def unit: Playground.Testing.Foo[Unit] = ???
  }
  implicit class EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T])
     extends Object() {
    T
    private[this] val io: cats.effect.IO[T]
    def asFoo(using 
      x$1:
        scala.util.NotGiven[
          <:<[EitherTOps.this.T,
            Either[? >: Nothing <: Any, ? >: Nothing <: Any]]
        ]
    ): Playground.Testing.Foo[EitherTOps.this.T] = ???
  }
  final implicit def EitherTOps[T >: Nothing <: Any](io: cats.effect.IO[T])
    : Playground.Testing.EitherTOps[T] =
    new Playground.Testing.EitherTOps[T](io)
  cats.syntax.apply.catsSyntaxApplyOps[
    [T] =>> cats.data.EitherT[cats.effect.IO, Exception, T], Unit](
    Playground.Testing.Foo.unit).*>[T](
    Playground.Testing.EitherTOps[T](
      cats.effect.IO.apply[Right[Nothing, Int]](Right.apply[Nothing, Int](5)
        )
    ).asFoo(scala.util.NotGiven.value)
  )(
    cats.data.EitherT.catsDataMonadErrorForEitherT[cats.effect.IO, Exception
      ](cats.effect.IO.asyncForIO)
  )
}

}
} of class class dotty.tools.dotc.ast.Trees$PackageDef

unhandled exception while running pickler on /tmp/scastie13261002748272130033/src/main/scala/main.scala

An unhandled exception was thrown in the compiler.
Please file a crash report here:
https://github.com/scala/scala3/issues/new/choose
For non-enriched exceptions, compile with -Xno-enrich-error-messages.

 while compiling: /tmp/scastie13261002748272130033/src/main/scala/main.scala
    during phase: pickler
            mode: Mode(ImplicitsEnabled)
 library version: version 2.13.16
compiler version: version 3.7.2
        settings: -classpath /tmp/scastie13261002748272130033/target/scala-3.7.2/classes:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.2/scala3-library_3-3.7.2.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/typelevel/cats-core_3/2.13.0/cats-core_3-2.13.0.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/typelevel/cats-effect_3/3.6.3/cats-effect_3-3.6.3.jar:/home/sbtRunnerContainer/.ivy2/local/org.scastie/runtime-scala_3/1.0.0-SNAPSHOT/jars/runtime-scala_3.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/typelevel/cats-kernel_3/2.13.0/cats-kernel_3-2.13.0.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/typelevel/cats-effect-kernel_3/3.6.3/cats-effect-kernel_3-3.6.3.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/typelevel/cats-effect-std_3/3.6.3/cats-effect-std_3-3.6.3.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/org/typelevel/cats-mtl_3/1.3.1/cats-mtl_3-1.3.1.jar:/home/sbtRunnerContainer/.ivy2/local/org.scastie/api_3/0.30.0-SNAPSHOT/jars/api_3.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-json_3/2.10.0-RC5/play-json_3-2.10.0-RC5.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/com/typesafe/play/play-functional_3/2.10.0-RC5/play-functional_3-2.10.0-RC5.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.11.4/jackson-core-2.11.4.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.11.4/jackson-annotations-2.11.4.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.11.4/jackson-datatype-jdk8-2.11.4.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.11.4/jackson-datatype-jsr310-2.11.4.jar:/home/sbtRunnerContainer/.cache/coursier/v1/https/repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.11.4/jackson-databind-2.11.4.jar -d /tmp/scastie13261002748272130033/target/scala-3.7.2/classes -deprecation true -feature true

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.