Skip to content

fix: Scala 3.9 context bound and trait field compatibility#3082

Draft
He-Pin wants to merge 3 commits into
apache:mainfrom
He-Pin:fix/scala-3.9-compat
Draft

fix: Scala 3.9 context bound and trait field compatibility#3082
He-Pin wants to merge 3 commits into
apache:mainfrom
He-Pin:fix/scala-3.9-compat

Conversation

@He-Pin

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

Copy link
Copy Markdown
Member

Motivation

Scala 3.9.0-RC1 introduces breaking changes:

  1. Context bound desugaring: [T: ClassTag] now desugars differently, making method(args)(ClassTag(clazz)) fail with "No ClassTag available for T"
  2. Trait field bytecode: private val in traits generates abstract setter methods with generic type signatures that mismatch between trait and implementing class, causing Java subclass compilation failures

Modification

  • actor-typed/Behaviors.scala: Use implicit val ct: ClassTag[T] = ClassTag(clazz) + implicit resolution instead of explicit ClassTag(clazz) passing for monitor, transformMessages, and withMdc methods
  • stream/Ops.scala: Use implicit val ls: LogSource[Materializer] = fromMaterializer + implicit resolution instead of explicit passing for Log and LogWithMarker preStart methods
  • actor/FSM.scala, persistence/PersistentFSMBase.scala: Change private val handleEventDefault to private def handleEventDefault to avoid abstract setter generation for this specific field

Result

Tests

  • sbt "++3.9.0-RC1!; compile" — ClassTag/LogSource errors resolved

References

Motivation:
Scala 3.9.0-RC1 changes context bound desugaring and trait field bytecode
generation. ClassTag/LogSource explicit passing via method(args)(ClassTag(x))
breaks, and private val in traits generates abstract setters visible to
Java subclasses.

Modification:
- Behaviors.scala: use implicit val ClassTag instead of explicit passing
  for monitor, transformMessages, and withMdc methods
- Ops.scala: use implicit val LogSource instead of explicit passing
  for Log and LogWithMarker preStart methods
- FSM.scala, PersistentFSMBase.scala: change private val handleEventDefault
  to private def to avoid abstract setter generation

Result:
ClassTag and LogSource context bound errors resolved. handleEventDefault
setter issue partially mitigated (remaining setters tracked in
scala/scala3#26372).

Tests:
- sbt "++3.9.0-RC1!; compile" resolves ClassTag/LogSource errors

References: scala/scala3#26372 - trait setter generic signature regression
@He-Pin He-Pin marked this pull request as draft June 18, 2026 11:06
* unhandled event handler
*/
private val handleEventDefault: StateFunction = {
private def handleEventDefault: StateFunction = {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will wait scala 3 fix

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we going to wait or will we log an issue to revert this when Scala team fix it?
We should link to the Scala bug.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scala/scala3#26374 @pjfanning maybe we can wait the RC2 ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's wait till scala RC2

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, have to wait, I want to make Pekko project 3.9.0 ready, then we can help capture new bugs

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I found Pekko's projects do help capture some bugs during the RC release

He-Pin added 2 commits June 18, 2026 19:20
Motivation:
Scala 3.9 removed the -Yfuture-lazy-vals compiler option as the behavior
is now the default. Passing this flag causes compilation errors on Scala 3.9+.

Modification:
Conditionally add -Yfuture-lazy-vals only when Scala minor version < 9
using CrossVersion.partialVersion check.

Result:
Project compiles on both Scala 3.3.x (which needs the flag) and
Scala 3.9+ (which has the behavior by default).
Motivation:
CI scalafmt check failed because project/PekkoBuild.scala was not formatted.

Modification:
Ran scalafmt on the build file.

Result:
scalafmtSbtCheck and Code is formatted CI checks should pass.

Tests:
Not run - formatting only
pjfanning
pjfanning previously approved these changes Jun 18, 2026

@pjfanning pjfanning left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@pjfanning pjfanning dismissed their stale review June 18, 2026 13:52

still in draft

@He-Pin He-Pin marked this pull request as ready for review June 18, 2026 17:26
@He-Pin He-Pin requested a review from pjfanning June 18, 2026 17:33
@He-Pin He-Pin marked this pull request as draft June 19, 2026 09:10
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.

2 participants