Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion compiler/src/dotty/tools/dotc/config/JavaPlatform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.*
import classpath.AggregateClassPath
import core.*
import Symbols.*, Types.*, Contexts.*, StdNames.*
import Phases.*
import Flags.*
import transform.ExplicitOuter

Expand Down Expand Up @@ -44,13 +45,29 @@ class JavaPlatform extends Platform {

def rootLoader(root: TermSymbol)(using Context): SymbolLoader = new SymbolLoaders.PackageLoader(root, classPath)

private def samMethodHasCompatibleBridge(cls: ClassSymbol)(using Context): Boolean =
cls.typeRef.possibleSamMethods match
case Seq(samMeth) =>
val samResultType = samMeth.info.resultType
if samResultType.isRef(defn.UnitClass) then
// If the result type of the SAM method is Unit, but the result type of the overridden
// methods is not Unit, the bridge will return Object, which is not compatible with Void
// required by LambdaMetaFactory.
// See issue #24573 for details.
samMeth.symbol.allOverriddenSymbols.forall(_.info.resultType.isRef(defn.UnitClass))
else true
case _ => false

/** Is the SAMType `cls` also a SAM under the rules of the JVM? */
def isSam(cls: ClassSymbol)(using Context): Boolean =
cls.isAllOf(NoInitsTrait) &&
cls.superClass == defn.ObjectClass &&
cls.directlyInheritedTraits.forall(_.is(NoInits)) &&
!ExplicitOuter.needsOuterIfReferenced(cls) &&
cls.typeRef.fields.isEmpty // Superaccessors already show up as abstract methods here, so no test necessary
// Superaccessors already show up as abstract methods here, so no test necessary
cls.typeRef.fields.isEmpty &&
// Check if SAM method will have a compatible bridge for LambdaMetaFactory
samMethodHasCompatibleBridge(cls)

/** We could get away with excluding BoxedBooleanClass for the
* purpose of equality testing since it need not compare equal
Expand Down
7 changes: 7 additions & 0 deletions tests/run/i24573.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
1
2
3
42
hello
world
!!
43 changes: 43 additions & 0 deletions tests/run/i24573.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
trait Con[-T] extends (T => Unit):
def apply(t: T): Unit

trait Con2[-T] extends (T => Int):
def apply(t: T): Int

trait Con3[+R] extends (() => R):
def apply(): R

trait F1[-T, +R]:
def apply(t: T): R

trait SF[-T] extends F1[T, Unit]:
def apply(t: T): Unit

trait F1U[-T]:
def apply(t: T): Unit

trait SF2 extends F1U[String]:
def apply(t: String): Unit

object Test:
def main(args: Array[String]): Unit =
val f1: (Int => Unit) = i => println(i)
f1(1)

val c1: Con[Int] = i => println(i)
c1(2)

val c2: Con2[Int] = i => { println(i); i }
c2(3)

val c3: Con3[Int] = () => 42
println(c3())

val c4: Con3[Unit] = () => println("hello")
c4()

val f5: SF[String] = s => println(s)
f5("world")

val f6: SF2 = i => println(i)
f6("!!")
Loading