Skip to content

Scala 3.9.0-RC4: trait private val with type alias still generates incompatible setter signature for Java subclasses #26616

Description

@He-Pin

Compiler version

Scala 3.9.0-RC4 (also affects 3.9.0-RC3, 3.9.0-RC1)

Minimized code

MyTrait.scala:

object MyTrait:
  case class Event[D](value: D)
  case class State[S, D](name: S, data: D)

trait MyTrait[S, D]:
  import MyTrait.*
  type StateT = State[S, D]
  type EventT = Event[D]
  type StateFunction = PartialFunction[EventT, StateT]
  private val handler: StateFunction = { case e => State(null.asInstanceOf[S], e.value) }

abstract class MyAbstract[S, D] extends MyTrait[S, D]

MyJavaClass.java:

public class MyJavaClass extends MyAbstract<String, String> {
}

Steps to reproduce

  1. Compile the Scala code:
    scalac -d out MyTrait.scala
    
  2. Compile the Java class:
    javac -cp out:$(cs fetch org.scala-lang:scala3-library_3:3.9.0-RC4 --classpath) MyJavaClass.java
    

Output

MyJavaClass.java:1: error: MyJavaClass is not abstract and does not override abstract method
MyTrait$_setter_$MyTrait$$handler_$eq(PartialFunction<Event<String>,State<String,String>>) in MyTrait
public class MyJavaClass extends MyAbstract<String, String> {
       ^

Expectation

The Java class should compile successfully, as it does with Scala 3.3.8.

Root cause analysis

This is a residual issue related to #26372 (fixed by #26374, regression fixed by #26542).

The fix in #26542 correctly handles cases where the trait type parameter is used directly in the field type. However, when the field type is expressed through type aliases defined inside the trait that expand to types containing the trait's type parameters, the mixed-in setter in the abstract class still gets Object types instead of the class's type variables.

Bytecode evidence (from Apache Pekko's FSM trait, same pattern):

Trait FSM[S, D] — abstract setter uses type variables:

Signature: (Lscala/PartialFunction<Lorg/apache/pekko/actor/FSM$Event<TD;>;Lorg/apache/pekko/actor/FSM$State<TS;TD;>;>;)V

Class AbstractFSM[S, D] — concrete setter uses Object:

Signature: (Lscala/PartialFunction<Lorg/apache/pekko/actor/FSM$Event<Ljava/lang/Object;>;Lorg/apache/pekko/actor/FSM$State<Ljava/lang/Object;Ljava/lang/Object;>;>;)V

The trait declares the abstract setter with TD/TS type variables, but the mixed-in concrete implementation in AbstractFSM widens them to Object. javac sees these as incompatible signatures and reports the abstract method as unimplemented.

Key difference from #26372: The field type uses trait-local type aliases (type StateFunction = PartialFunction[EventT, StateT] where EventT = Event[D], StateT = State[S, D]). The mixinGenericInfos logic in Mixin.scala appears to not substitute type parameters when they are reached through type alias expansion.

Workaround

None for library authors — the trait must be restructured to avoid type aliases in private val types, which is invasive.

Context

This blocks Apache Pekko's Scala 3.9.0-RC4 cross-compilation (apache/pekko#3303). The FSM[S, D] trait and PersistentFSMBase both use this pattern extensively.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

compat:javaitype:bugregressionThis worked in a previous version but doesn't anymorestat:needs bisectionNeed to use nightly builds and git bisect to find out the commit where this issue was introduced

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions