Skip to content

Fix Scala 3.8.4 compilation compatibility while preserving 2.13 and 3.3.x cross-build#3060

Draft
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:scala3-upgrade-fix-warnings
Draft

Fix Scala 3.8.4 compilation compatibility while preserving 2.13 and 3.3.x cross-build#3060
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:scala3-upgrade-fix-warnings

Conversation

@He-Pin

@He-Pin He-Pin commented Jun 13, 2026

Copy link
Copy Markdown
Member

Motivation

The codebase needs to compile with both Scala 3.3.x (current production) and Scala 3.8.4 (forward compatibility for the upcoming 3.9 LTS). Several patterns in the codebase break under Scala 3.8 due to changes in how context bounds are desugared (they become using clauses), stricter deprecation warnings, and syntax changes.

Modification

171 files changed across the codebase:

  • ClassTag context bound fixes: In Scala 3.8, [T: ClassTag] desugars to a using clause, making explicit ClassTag passing positional-incompatible. Fixed by using implicit val ct: ClassTag[T] = ClassTag(clazz) in scope and relying on implicit resolution instead of explicit passing. Key files: PersistencePlugin.scala, EventSourcedBehaviorTestKit.scala, ActorContextSpec.scala, BehaviorTestKitSpec.scala, Behavior.scala, EventStream.scala, Topic.scala, ShardingProducerController.scala, ShardedDaemonProcessImpl.scala, StreamTestKit.scala.

  • PersistencePlugin implicit parameter merge: Merged [T: ClassTag] context bound and (implicit ev: PluginProvider[...]) into a single implicit parameter list (implicit ct: ClassTag[T], ev: PluginProvider[T, ScalaDsl, JavaDsl]) to avoid context bound + separate implicit parameter mismatch in Scala 3.8.

  • .apply() trick: Used decoration[T].apply(behavior) instead of decoration[T](behavior) to separate implicit resolution from function application (Scala 2.13 interprets (behavior) as the implicit ClassTag argument).

  • private[this]private: Scala 3.8 deprecates private[this] in favor of private.

  • = _ initializers → explicit defaults: Replaced = _ with = null, = None, = 0, etc. as Scala 3.8 deprecates uninitialized vars.

  • SortedSet.empty(ordering) fix: Bound ordering as implicit val ord before calling .empty[Member] to avoid implicit resolution issues.

  • @unchecked annotations: Added for type-test patterns that can't be checked at runtime under Scala 3.

  • @nowarn filters: Used message-based @nowarn("msg=never used") instead of category-based filters for cross-version compatibility.

  • PekkoDisciplinePlugin.scala: Added -Wconf suppression rules for Scala 3.8 deprecation/syntax warnings in both main and test scopes.

  • No using keyword in shared sources: All changes use cross-compatible patterns (implicit val, .apply() trick). The using keyword only appears in scala-3/ directories.

Result

All modules compile with both Scala 2.13.18 and Scala 3.8.4. Production Scala 3 version remains at 3.3.8 — this change only ensures forward compatibility. No behavioral changes to the runtime.

Tests

  • sbt "++3.8.4" "Test / compile" — success across all modules
  • sbt "Test / compile" (Scala 2.13.18) — success across all modules

References

None - proactive Scala 3.8 forward compatibility

@He-Pin He-Pin force-pushed the scala3-upgrade-fix-warnings branch from 812a6d1 to 913415e Compare June 13, 2026 17:49
… cross-build

Motivation:
The codebase needs to compile with both Scala 3.3.x (current production) and
Scala 3.8.4 (forward compatibility for upcoming 3.9 LTS). Several patterns
valid in 3.3.x are errors or warnings in 3.8.4.

Modification:
- Merge PersistencePlugin [T: ClassTag] context bound and (implicit ev:
  PluginProvider) into a single implicit parameter list so subclasses can
  pass both arguments without the `using` keyword (cross-compatible with
  Scala 2.13 and 3.3.x)
- Replace explicit ClassTag passing `method(arg)(ClassTag(clazz))` with
  `implicit val ct = ClassTag(clazz); method(arg)` pattern throughout the
  codebase (context bounds become `using` clauses in Scala 3.8, making
  positional passing an error)
- Fix SortedSet.empty(ordering) / TreeSet.empty(ordering) across cluster,
  cluster-tools, cluster-sharding, distributed-data modules by binding the
  Ordering as an implicit val before calling .empty[Member]
- Add @unchecked to type-test patterns that cannot be checked at runtime
  (Reachability.scala, AskPattern.scala)
- Fix `_` wildcard type argument to `?` in scala-3-only source files
- Fix LogSource resolution in MultiNodeSpec (classOf instead of this.getClass)
- Fix "pure expression does nothing" in FixedBufferSpec structural type calls
- Remove discarded non-Unit value (unused Success) in SnapshotStorage
- Add -Wconf suppression rules for Scala 3.8 deprecation and syntax warnings
  in PekkoDisciplinePlugin (both main and test scopes)

Result:
All modules compile successfully with both Scala 2.13.18 and Scala 3.8.4.
Cross-compilation with Scala 2.13 is preserved. No `using` keyword is used
in shared source files.

Tests:
- sbt "++3.8.4" "Test / compile" — success
- sbt "Test / compile" (2.13) — success (docs module has pre-existing unused warnings)

References:
None - proactive Scala 3.8 forward compatibility
@He-Pin He-Pin force-pushed the scala3-upgrade-fix-warnings branch from 913415e to 462dff8 Compare June 13, 2026 18:19
@He-Pin He-Pin marked this pull request as draft June 13, 2026 18:22
@He-Pin He-Pin marked this pull request as ready for review June 13, 2026 18:28
@He-Pin He-Pin added this to the 2.0.0-M4 milestone Jun 13, 2026
@He-Pin He-Pin requested review from mdedetrich and pjfanning June 13, 2026 18:41
He-Pin added a commit that referenced this pull request Jun 13, 2026
…ations

Motivation:
The initial Scala 3.8 compatibility changes had some code duplication,
unnecessary type casts, and could be simplified in several places.

Modification:
- Extract shared isScala3_8Plus method in JdkOptions to eliminate
  duplication with Jdk9.scala
- Re-add Scala 3.8 -Wconf suppressions in PekkoDisciplinePlugin with
  deduplication using shared scala3Suppressions/scala3DocSuppressions
- Simplify BehaviorTestKitSpec messageAdapter by removing unnecessary
  asInstanceOf and using proper ClassTag[U] type parameter
- Simplify ActorContextSpec ClassTag.Null passing by using explicit
  parameter instead of implicit val with @nowarn

Result:
Cleaner, more maintainable Scala 3.8 compatibility code with less
duplication and unnecessary type casts.

Tests:
Not run - code simplifications only, no behavior changes

References:
Refs #3060
He-Pin added a commit that referenced this pull request Jun 13, 2026
…estKit

Motivation:
PR #3060 CI was failing with two categories of errors on Scala 2.13:
1. ~100 fatal warnings in docs/Test/compile from unused imports, locals,
   and pattern variables that were not suppressed
2. "not found: type U" in BehaviorTestKitSpec due to type erasure in
   pattern matching

Modification:
- PekkoDisciplinePlugin: add docsScala2Suppressions with explicit -Wconf
  rules for each unused subcategory (unused-imports, unused-locals,
  unused-pat-vars, etc.) because Scala 2.13's -Wconf uses exact string
  matching, so cat=unused:s does not match subcategories
- BehaviorTestKitSpec: revert ClassTag[U] change back to explicit
  ClassTag(messageClass) passing since U is not in scope during
  pattern matching of CreateMessageAdapter

Result:
docs/Test/compile and actor-testkit-typed/Test/compile pass on both
Scala 2.13.18 and 3.3.8

Tests:
- sbt "++ 2.13.18 docs/Test/compile" — success (30 compilation units)
- sbt "++ 3.3.8 docs/Test/compile" — success
- sbt "++ 2.13.18 actor-testkit-typed/Test/compile" — success
- sbt "++ 3.3.8 actor-testkit-typed/Test/compile" — success

References:
Fixes CI failures on PR #3060
@He-Pin He-Pin removed this from the 2.0.0-M4 milestone Jun 13, 2026
@He-Pin He-Pin marked this pull request as draft June 13, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant