Summary
Starting with cats-effect 3.7.0, on Scala 2.12 and 2.13 a downstream project can no longer compile a subclass of cats.effect.kernel.Async unless it also adds scalac-compat-annotation to its own classpath.
In 3.7.0, Async#syncStep changed from @nowarn("msg=never used") on the method to @unused (org.typelevel.scalaccompat.annotation.unused) on the limit parameter. cats-effect-kernel declares scalac-compat-annotation with <scope>provided</scope>, so downstream projects don't get it transitively. When scalac 2.x type-checks a class that extends Async, it loads the parameter annotations of the inherited syncStep and fails with a missing symbol.
Affected versions
- cats-effect-kernel 3.7.0 and 3.7.1 (
Async.scala on series/3.x still has the same code)
- Scala 2.12.21; sbt 1.11.7; JDK 17 / 21
- Scala 2.13.18 is affected as well, with
scalaVersion := "2.13.18" in the same build. Its error is Symbol 'type org.typelevel.scalaccompat.annotation.package.unused' is missing from the classpath, reported at the import.
- 3.6.3 is not affected. Scala 3.3.7 is not affected.
Minimal reproduction
project/build.properties:
build.sbt:
scalaVersion := "2.12.21"
libraryDependencies += "org.typelevel" %% "cats-effect-kernel" % "3.7.1"
scalacOptions += "-language:higherKinds"
src/main/scala/Repro.scala:
import cats.effect.kernel.Async
abstract class MyAsync[F[_]] extends Async[F]
Run sbt compile.
Observed
[error] /repro/src/main/scala/Repro.scala:3:38: Symbol 'type org.typelevel.scalaccompat.annotation.unused' is missing from the classpath.
[error] This symbol is required by ' <none>'.
[error] Make sure that type unused is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'Async.class' was compiled against an incompatible version of org.typelevel.scalaccompat.annotation.
[error] abstract class MyAsync[F[_]] extends Async[F]
[error] ^
[error] one error found
Expected
It compiles, as it does with cats-effect-kernel 3.6.3, which you can check by changing only the version.
Workaround
Add the annotation library to the downstream build:
libraryDependencies += "org.typelevel" %% "scalac-compat-annotation" % "0.1.4" % Provided
Possible fixes
Either go back to a method-level @nowarn for syncStep (as in 3.6.x), or stop declaring scalac-compat-annotation as provided for artifacts whose public signatures carry its annotations.
Summary
Starting with cats-effect 3.7.0, on Scala 2.12 and 2.13 a downstream project can no longer compile a subclass of
cats.effect.kernel.Asyncunless it also addsscalac-compat-annotationto its own classpath.In 3.7.0,
Async#syncStepchanged from@nowarn("msg=never used")on the method to@unused(org.typelevel.scalaccompat.annotation.unused) on thelimitparameter.cats-effect-kerneldeclaresscalac-compat-annotationwith<scope>provided</scope>, so downstream projects don't get it transitively. When scalac 2.x type-checks a class that extendsAsync, it loads the parameter annotations of the inheritedsyncStepand fails with a missing symbol.Affected versions
Async.scalaonseries/3.xstill has the same code)scalaVersion := "2.13.18"in the same build. Its error isSymbol 'type org.typelevel.scalaccompat.annotation.package.unused' is missing from the classpath, reported at the import.Minimal reproduction
project/build.properties:build.sbt:src/main/scala/Repro.scala:Run
sbt compile.Observed
Expected
It compiles, as it does with
cats-effect-kernel3.6.3, which you can check by changing only the version.Workaround
Add the annotation library to the downstream build:
Possible fixes
Either go back to a method-level
@nowarnforsyncStep(as in 3.6.x), or stop declaringscalac-compat-annotationasprovidedfor artifacts whose public signatures carry its annotations.