From e280b282f568025fc07a3893ec3666a7ef5b9a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=99=8E=E9=B8=A3?= Date: Mon, 15 Jun 2026 22:23:02 +0800 Subject: [PATCH] fix: Scala 3.8 forward compatibility for context bounds and build config Motivation: Scala 3.8 changes how context parameters work: context bound evidence can no longer be passed explicitly using the old syntax. Additionally, several scalac flags (-language:_, -Ywarn-dead-code) are Scala 2-only. Modification: - Fix context bound patterns: replace explicit passing (Tuple.yes, ev, OutIsTuple, ClassTag, LogSource) with implicit vals in scope - Fix routing DSL: Directive (or, validatedMap, tmap, tcollect), PathMatcher (provide, apply), PathDirectives (rawPathPrefix, pathSuffix), FutureDirectives (OnSuccessMagnet) - Fix core: HttpMessage.getHeaders ClassTag, RejectionHandler ClassTag, PoolInterface/StageLoggingWithOverride LogSource - Fix testkit: TestRouteResult, RouteTest ClassTag bounds - Build config: move -Ywarn-dead-code/-Xlint to Scala 2-only, add -Wconf suppressions for Scala 3, make -language:_ conditional, replace -Xfatal-warnings with -Werror in docs - Fix test code: EntityStreamingSpec implicit passing Result: All modules compile cleanly on Scala 2.13.18 and 3.3.8, with source compatibility for Scala 3.8's context parameter changes. Tests: - sbt "++ 2.13 Test/compile" passes - sbt "++ 3.3 Test/compile" passes References: None - Scala 3.8 forward compatibility --- build.sbt | 8 ++--- .../impl/engine/client/PoolInterface.scala | 5 ++- .../impl/util/StageLoggingWithOverride.scala | 6 ++-- .../http/scaladsl/model/HttpMessage.scala | 3 +- .../javadsl/testkit/TestRouteResult.scala | 6 ++-- .../http/scaladsl/testkit/RouteTest.scala | 2 +- .../remote/testkit/MultiNodeConfig.scala | 3 +- ...ntLeakActorsOnFailingConnectionSpecs.scala | 3 +- .../scaladsl/server/EntityStreamingSpec.scala | 9 +++-- .../javadsl/server/RejectionHandler.scala | 6 ++-- .../http/scaladsl/server/Directive.scala | 36 ++++++++++++------- .../http/scaladsl/server/PathMatcher.scala | 8 ++--- .../server/directives/FutureDirectives.scala | 4 ++- .../server/directives/PathDirectives.scala | 4 +-- project/Common.scala | 16 +++++++-- 15 files changed, 80 insertions(+), 39 deletions(-) diff --git a/build.sbt b/build.sbt index bed8bb90c9..39b78ffb14 100644 --- a/build.sbt +++ b/build.sbt @@ -108,7 +108,7 @@ lazy val parsing = project("parsing") .settings(AutomaticModuleName.settings("pekko.http.parsing")) .addPekkoModuleDependency("pekko-actor", "provided", PekkoCoreDependency.default) .settings(Dependencies.parsing) - .settings(scalacOptions += "-language:_") + .settings(scalacOptions ++= (if (scalaVersion.value.startsWith("3")) Nil else Seq("-language:_"))) .settings(scalaMacroSupport) .enablePlugins(ScaladocNoVerificationOfDiagrams) .enablePlugins(ReproducibleBuildsPlugin) @@ -136,7 +136,7 @@ lazy val http = project("http") .addPekkoModuleDependency("pekko-stream", "provided", PekkoCoreDependency.default) .settings(Dependencies.http) .settings( - Compile / scalacOptions += "-language:_") + Compile / scalacOptions ++= (if (scalaVersion.value.startsWith("3")) Nil else Seq("-language:_"))) .settings(scalaMacroSupport) .enablePlugins(BootstrapGenjavadoc, BoilerplatePlugin) .enablePlugins(ReproducibleBuildsPlugin) @@ -191,7 +191,7 @@ lazy val httpTestkit = project("http-testkit") .settings( // don't ignore Suites which is the default for the junit-interface testOptions += Tests.Argument(TestFrameworks.JUnit, "--ignore-runners="), - Compile / scalacOptions ++= Seq("-language:_"), + Compile / scalacOptions ++= (if (scalaVersion.value.startsWith("3")) Nil else Seq("-language:_")), Test / run / mainClass := Some("org.apache.pekko.http.javadsl.SimpleServerApp")) .enablePlugins(BootstrapGenjavadoc, MultiNodeScalaTest, ScaladocNoVerificationOfDiagrams) .enablePlugins(ReproducibleBuildsPlugin) @@ -398,7 +398,7 @@ lazy val docs = project("docs") name := "pekko-http-docs", scalacOptions ++= Seq( // Make sure we don't accidentally keep documenting deprecated calls - "-Xfatal-warnings", + "-Werror", // Does not appear to lead to problems "-Wconf:msg=The outer reference in this type test cannot be checked at run time:s"), scalacOptions ++= ( diff --git a/http-core/src/main/scala/org/apache/pekko/http/impl/engine/client/PoolInterface.scala b/http-core/src/main/scala/org/apache/pekko/http/impl/engine/client/PoolInterface.scala index 626d50a395..4ab84a59e4 100644 --- a/http-core/src/main/scala/org/apache/pekko/http/impl/engine/client/PoolInterface.scala +++ b/http-core/src/main/scala/org/apache/pekko/http/impl/engine/client/PoolInterface.scala @@ -67,7 +67,10 @@ private[http] object PoolInterface { import hcps._ import setup.{ connectionContext, settings } implicit val system = fm.system - val log: LoggingAdapter = Logging(system, poolId)(PoolLogSource) + val log: LoggingAdapter = { + implicit val ls: LogSource[PoolId] = PoolLogSource + Logging(system, poolId) + } log.debug("Creating pool.") diff --git a/http-core/src/main/scala/org/apache/pekko/http/impl/util/StageLoggingWithOverride.scala b/http-core/src/main/scala/org/apache/pekko/http/impl/util/StageLoggingWithOverride.scala index 731d1e7f4b..89c21dc9dd 100644 --- a/http-core/src/main/scala/org/apache/pekko/http/impl/util/StageLoggingWithOverride.scala +++ b/http-core/src/main/scala/org/apache/pekko/http/impl/util/StageLoggingWithOverride.scala @@ -41,8 +41,10 @@ private[pekko] trait StageLoggingWithOverride extends GraphStageLogic { case null => _log = logOverride match { - case DefaultNoLogging => - pekko.event.Logging(materializer.system, logSource)(LogSource.fromClass) + case DefaultNoLogging => { + implicit val classLogSource: LogSource[Class[?]] = LogSource.fromClass + pekko.event.Logging(materializer.system, logSource: Class[?]) + } case x => x } case _ => diff --git a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala index 97e6f916b9..ce7a28f0fb 100644 --- a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala +++ b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala @@ -213,7 +213,8 @@ sealed trait HttpMessage extends jm.HttpMessage { /** Java API */ def getHeaders[T <: jm.HttpHeader](headerClass: Class[T]): JIterable[T] = { - headers[T](ClassTag[T](headerClass)).asJava + implicit val ct: ClassTag[T] = ClassTag(headerClass) + headers[T].asJava } /** Java API */ diff --git a/http-testkit/src/main/scala/org/apache/pekko/http/javadsl/testkit/TestRouteResult.scala b/http-testkit/src/main/scala/org/apache/pekko/http/javadsl/testkit/TestRouteResult.scala index 8ad880b4aa..c75986703d 100644 --- a/http-testkit/src/main/scala/org/apache/pekko/http/javadsl/testkit/TestRouteResult.scala +++ b/http-testkit/src/main/scala/org/apache/pekko/http/javadsl/testkit/TestRouteResult.scala @@ -113,9 +113,11 @@ abstract class TestRouteResult(_result: Future[RouteResult], awaitAtMost: Finite /** * Returns the first header of the response which is of the given class. */ - def header[T >: Null <: HttpHeader](clazz: Class[T]): T = - response.header(ClassTag(clazz)) + def header[T >: Null <: HttpHeader](clazz: Class[T]): T = { + implicit val ct: ClassTag[T] = ClassTag(clazz) + response.header[T] .getOrElse(doFail(s"Expected header of type ${clazz.getSimpleName} but wasn't found.")) + } /** * Expects the route to have been rejected, returning the list of rejections, or empty list if the route diff --git a/http-testkit/src/main/scala/org/apache/pekko/http/scaladsl/testkit/RouteTest.scala b/http-testkit/src/main/scala/org/apache/pekko/http/scaladsl/testkit/RouteTest.scala index 8fa833417d..5f0e33106d 100644 --- a/http-testkit/src/main/scala/org/apache/pekko/http/scaladsl/testkit/RouteTest.scala +++ b/http-testkit/src/main/scala/org/apache/pekko/http/scaladsl/testkit/RouteTest.scala @@ -95,7 +95,7 @@ trait RouteTest extends RequestBuilding with WSTestRequestBuilding with RouteTes def charsetOption: Option[HttpCharset] = contentType.charsetOption def charset: HttpCharset = charsetOption.getOrElse(sys.error("Binary entity does not have charset")) def headers: immutable.Seq[HttpHeader] = rawResponse.headers - def header[T >: Null <: HttpHeader: ClassTag]: Option[T] = rawResponse.header[T](implicitly[ClassTag[T]]) + def header[T >: Null <: HttpHeader: ClassTag]: Option[T] = rawResponse.header[T] def header(name: String): Option[HttpHeader] = rawResponse.headers.find(_.is(name.toLowerCase)) def status: StatusCode = rawResponse.status diff --git a/http-tests/src/multi-jvm/scala/org/apache/pekko/remote/testkit/MultiNodeConfig.scala b/http-tests/src/multi-jvm/scala/org/apache/pekko/remote/testkit/MultiNodeConfig.scala index 7f020d6cb7..d48fb216f3 100644 --- a/http-tests/src/multi-jvm/scala/org/apache/pekko/remote/testkit/MultiNodeConfig.scala +++ b/http-tests/src/multi-jvm/scala/org/apache/pekko/remote/testkit/MultiNodeConfig.scala @@ -273,7 +273,8 @@ abstract class MultiNodeSpec(val myself: RoleName, _system: ActorSystem, _roles: ActorSystem(MultiNodeSpec.getCallerName(classOf[MultiNodeSpec]), ConfigFactory.load(config.config)), config.roles, config.deployments) - val log: LoggingAdapter = Logging(system, this.getClass)(LogSource.fromClass) + implicit val classLogSource: LogSource[Class[?]] = LogSource.fromClass + val log: LoggingAdapter = Logging(system, this.getClass: Class[?]) /** * Enrich `.await()` onto all Awaitables, using remaining duration from the innermost diff --git a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/DontLeakActorsOnFailingConnectionSpecs.scala b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/DontLeakActorsOnFailingConnectionSpecs.scala index b2b44aca19..92337e07f5 100644 --- a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/DontLeakActorsOnFailingConnectionSpecs.scala +++ b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/DontLeakActorsOnFailingConnectionSpecs.scala @@ -52,7 +52,8 @@ abstract class DontLeakActorsOnFailingConnectionSpecs(poolImplementation: String implicit val system: ActorSystem = ActorSystem("DontLeakActorsOnFailingConnectionSpecs-" + poolImplementation, config) implicit val materializer: Materializer = Materializer.createMaterializer(system) - val log = Logging(system, getClass)(LogSource.fromClass) + implicit val classLogSource: LogSource[Class[?]] = LogSource.fromClass + val log = Logging(system, getClass: Class[?]) "Http.superPool" should { diff --git a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/EntityStreamingSpec.scala b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/EntityStreamingSpec.scala index 7099d811fb..2fb73abdd6 100755 --- a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/EntityStreamingSpec.scala +++ b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/server/EntityStreamingSpec.scala @@ -398,9 +398,12 @@ class EntityStreamingSpec extends RoutingSpec with ScalaFutures { val jsonStreamingSupport: JsonEntityStreamingSupport = EntityStreamingSupport.json() - implicit val toResponseMarshaller: ToResponseMarshaller[Source[String, NotUsed]] = - PredefinedToResponseMarshallers.fromEntityStreamingSupportAndByteStringMarshaller[String, NotUsed]( - scala.reflect.classTag[String], jsonStreamingSupport, csvStringMarshaller) + implicit val toResponseMarshaller: ToResponseMarshaller[Source[String, NotUsed]] = { + implicit val ct: scala.reflect.ClassTag[String] = scala.reflect.ClassTag(classOf[String]) + implicit val ess: EntityStreamingSupport = jsonStreamingSupport + implicit val tbsm: ToByteStringMarshaller[String] = csvStringMarshaller + PredefinedToResponseMarshallers.fromEntityStreamingSupportAndByteStringMarshaller[String, NotUsed] + } val route = get { diff --git a/http/src/main/scala/org/apache/pekko/http/javadsl/server/RejectionHandler.scala b/http/src/main/scala/org/apache/pekko/http/javadsl/server/RejectionHandler.scala index fcc650e438..9bb53c8e0f 100644 --- a/http/src/main/scala/org/apache/pekko/http/javadsl/server/RejectionHandler.scala +++ b/http/src/main/scala/org/apache/pekko/http/javadsl/server/RejectionHandler.scala @@ -69,8 +69,10 @@ class RejectionHandlerBuilder(asScala: server.RejectionHandler.Builder) { */ def handleAll[T <: Rejection]( t: Class[T], handler: function.Function[java.util.List[T], Route]): RejectionHandlerBuilder = { - asScala.handleAll { (rejections: collection.immutable.Seq[T]) => handler.apply(rejections.asJava).delegate }( - ClassTag(t)) + implicit val ct: ClassTag[server.Rejection] = ClassTag(t) + asScala.handleAll { (rejections: collection.immutable.Seq[server.Rejection]) => + handler.apply(rejections.asInstanceOf[Seq[T]].asJava).delegate + } this } diff --git a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Directive.scala b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Directive.scala index 2e5493da71..0938faa950 100644 --- a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Directive.scala +++ b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/Directive.scala @@ -48,8 +48,10 @@ abstract class Directive[L](implicit val ev: Tuple[L]) { /** * Joins two directives into one which runs the second directive if the first one rejects. */ - def or[R >: L](that: Directive[R]): Directive[R] = - recover(rejections => directives.BasicDirectives.mapRejections(rejections ++ _) & that)(that.ev) + def or[R >: L](that: Directive[R]): Directive[R] = { + implicit val ev: Tuple[R] = that.ev + recover(rejections => directives.BasicDirectives.mapRejections(rejections ++ _) & that) + } /** * Joins two directives into one which extracts the concatenation of its base directive extractions. @@ -70,7 +72,8 @@ abstract class Directive[L](implicit val ev: Tuple[L]) { * instance of type `A` (which is usually a case class). */ def as[A](constructor: ConstructFromTuple[L, A]): Directive1[A] = { - def validatedMap[R](f: L => R)(implicit tupler: Tupler[R]): Directive[tupler.Out] = + def validatedMap[R](f: L => R)(implicit tupler: Tupler[R]): Directive[tupler.Out] = { + implicit val tupleEv: Tuple[tupler.Out] = tupler.OutIsTuple Directive[tupler.Out] { inner => tapply { values => ctx => def futureRouteResult(): Future[RouteResult] = { @@ -84,7 +87,8 @@ abstract class Directive[L](implicit val ev: Tuple[L]) { } futureRouteResult() } - }(tupler.OutIsTuple) + } + } validatedMap(constructor) } @@ -93,8 +97,10 @@ abstract class Directive[L](implicit val ev: Tuple[L]) { * Maps over this directive using the given function, which can produce either a tuple or any other value * (which will then we wrapped into a [[scala.Tuple1]]). */ - def tmap[R](f: L => R)(implicit tupler: Tupler[R]): Directive[tupler.Out] = - Directive[tupler.Out] { inner => tapply { values => inner(tupler(f(values))) } }(tupler.OutIsTuple) + def tmap[R](f: L => R)(implicit tupler: Tupler[R]): Directive[tupler.Out] = { + implicit val tupleEv: Tuple[tupler.Out] = tupler.OutIsTuple + Directive[tupler.Out] { inner => tapply { values => inner(tupler(f(values))) } } + } /** * Flatmaps this directive using the given function. @@ -124,12 +130,14 @@ abstract class Directive[L](implicit val ev: Tuple[L]) { * If it is not defined however, the returned directive will reject with the given rejections. */ def tcollect[R](pf: PartialFunction[L, R], rejections: Rejection*)( - implicit tupler: Tupler[R]): Directive[tupler.Out] = + implicit tupler: Tupler[R]): Directive[tupler.Out] = { + implicit val tupleEv: Tuple[tupler.Out] = tupler.OutIsTuple Directive[tupler.Out] { inner => tapply { values => ctx => { if (pf.isDefinedAt(values)) inner(tupler(pf(values)))(ctx) else ctx.reject(rejections: _*) } } - }(tupler.OutIsTuple) + } + } /** * Creates a new directive that is able to recover from rejections that were produced by `this` Directive @@ -188,10 +196,12 @@ object Directive { * Adds helper functions to `Directive0` */ implicit class Directive0Support(val underlying: Directive0) extends AnyVal { - def wrap[R](f: => Directive[R]): Directive[R] = + def wrap[R](f: => Directive[R]): Directive[R] = { + implicit val tupleEv: Tuple[R] = Tuple.yes[R] underlying.tflatMap { _ => f - }(Tuple.yes[R]) // we will create a Directive[R], so we know it will be tupled correctly + } // we will create a Directive[R], so we know it will be tupled correctly + } } /** @@ -251,10 +261,12 @@ object ConjunctionMagnet { implicit join: TupleOps.Join[L, R]): ConjunctionMagnet[L] { type Out = Directive[join.Out] } = new ConjunctionMagnet[L] { type Out = Directive[join.Out] - def apply(underlying: Directive[L]) = + def apply(underlying: Directive[L]) = { + implicit val joinOutIsTuple: Tuple[join.Out] = Tuple.yes[join.Out] Directive[join.Out] { inner => underlying.tapply { prefix => other.tapply { suffix => inner(join(prefix, suffix)) } } - }(Tuple.yes) // we know that join will only ever produce tuples + } + } } implicit def fromStandardRoute[L](route: StandardRoute): ConjunctionMagnet[L] { type Out = StandardRoute } = diff --git a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/PathMatcher.scala b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/PathMatcher.scala index e1e5fd1f83..147d22fd9e 100644 --- a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/PathMatcher.scala +++ b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/PathMatcher.scala @@ -156,20 +156,20 @@ object PathMatcher extends ImplicitPathMatcherConstruction { /** * Creates a PathMatcher that always matches, consumes nothing and extracts the given Tuple of values. */ - def provide[L: Tuple](extractions: L): PathMatcher[L] = + def provide[L](extractions: L)(implicit ev: Tuple[L]): PathMatcher[L] = new PathMatcher[L] { - def apply(path: Path) = Matched(path, extractions)(ev) + def apply(path: Path) = Matched(path, extractions) } /** * Creates a PathMatcher that matches and consumes the given path prefix and extracts the given list of extractions. * If the given prefix is empty the returned PathMatcher matches always and consumes nothing. */ - def apply[L: Tuple](prefix: Path, extractions: L): PathMatcher[L] = + def apply[L](prefix: Path, extractions: L)(implicit ev: Tuple[L]): PathMatcher[L] = if (prefix.isEmpty) provide(extractions) else new PathMatcher[L] { def apply(path: Path) = - if (path.startsWith(prefix)) Matched(path.dropChars(prefix.charCount), extractions)(ev) + if (path.startsWith(prefix)) Matched(path.dropChars(prefix.charCount), extractions) else Unmatched } diff --git a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/FutureDirectives.scala b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/FutureDirectives.scala index e65fbc58b9..5259c665cb 100644 --- a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/FutureDirectives.scala +++ b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/FutureDirectives.scala @@ -20,6 +20,7 @@ import scala.util.{ Failure, Success, Try } import org.apache.pekko import pekko.http.scaladsl.marshalling.ToResponseMarshaller import pekko.http.scaladsl.server.Directives._ +import pekko.http.scaladsl.server.util.Tuple import pekko.http.scaladsl.server.util.Tupler import pekko.http.scaladsl.util.FastFuture._ import pekko.pattern.{ CircuitBreaker, CircuitBreakerOpenException } @@ -102,10 +103,11 @@ object OnSuccessMagnet { implicit def apply[T](future: => Future[T])(implicit tupler: Tupler[T]): OnSuccessMagnet { type Out = tupler.Out } = new OnSuccessMagnet { type Out = tupler.Out + implicit val tupleEv: Tuple[tupler.Out] = tupler.OutIsTuple val directive = Directive[tupler.Out] { inner => ctx => import ctx.executionContext future.fast.flatMap(t => inner(tupler(t))(ctx)) - }(tupler.OutIsTuple) + } } } diff --git a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/PathDirectives.scala b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/PathDirectives.scala index 54a84477e7..b2f4297c53 100644 --- a/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/PathDirectives.scala +++ b/http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/PathDirectives.scala @@ -61,7 +61,7 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w def rawPathPrefix[L](pm: PathMatcher[L]): Directive[L] = { implicit val LIsTuple = pm.ev extract(ctx => pm(ctx.unmatchedPath)).flatMap { - case Matched(rest, values) => tprovide(values)(LIsTuple) & mapRequestContext(_.withUnmatchedPath(rest)) + case Matched(rest, values) => tprovide[L](values) & mapRequestContext(_.withUnmatchedPath(rest)) case Unmatched => reject } } @@ -100,7 +100,7 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w def pathSuffix[L](pm: PathMatcher[L]): Directive[L] = { implicit val LIsTuple = pm.ev extract(ctx => pm(ctx.unmatchedPath.reverse)).flatMap { - case Matched(rest, values) => tprovide(values)(LIsTuple) & mapRequestContext(_.withUnmatchedPath(rest.reverse)) + case Matched(rest, values) => tprovide[L](values) & mapRequestContext(_.withUnmatchedPath(rest.reverse)) case Unmatched => reject } } diff --git a/project/Common.scala b/project/Common.scala index 8558bc9fa2..c7b82ecd4c 100644 --- a/project/Common.scala +++ b/project/Common.scala @@ -24,11 +24,11 @@ object Common extends AutoPlugin { "-deprecation", "-encoding", "UTF-8", // yes, this is 2 args "-unchecked", - "-Ywarn-dead-code", "-Wconf:msg=reached max recursion depth:s", "-Wconf:msg=Prefer the Scala annotation over Java's `@Deprecated`:s", "-release:" + javacTarget), scalacOptions ++= onlyOnScala2(Seq( + "-Ywarn-dead-code", "-Xlint", // Exhaustivity checking is only useful for simple sealed hierarchies and matches without filters. // In all other cases, the warning is non-actionable: you get spurious warnings that need to be suppressed @@ -36,7 +36,19 @@ object Common extends AutoPlugin { "-Wconf:cat=other-match-analysis&msg=match may not be exhaustive:s")).value, scalacOptions ++= onlyOnScala3(Seq( "-Wconf:cat=deprecation:s", - "-Yfuture-lazy-vals")).value, + "-Yfuture-lazy-vals", + "-Wconf:msg=Implicit parameters should be provided with a `using` clause:s", + "-Wconf:msg=is deprecated for wildcard arguments of types:s", + "-Wconf:msg=The trailing ` _` for eta-expansion is unnecessary:s", + "-Wconf:msg=with as a type operator has been deprecated:s", + "-Wconf:msg=Unreachable case except for null:s", + "-Wconf:msg=is no longer supported for vararg splices:s", + "-Wconf:msg=is not declared infix:s", + "-Wconf:msg=auto insertion will be deprecated:s", + "-Wconf:msg=Ignoring \\[this\\] qualifier:s", + "-Wconf:msg=trait App in package scala is deprecated:s", + "-Wconf:msg=pattern binding uses refutable extractor:s", + "-Wconf:msg=bad option.*-Yfuture-lazy-vals:s")).value, javacOptions ++= Seq("-encoding", "UTF-8", "--release", javacTarget), mimaReportSignatureProblems := true,