Skip to content

Commit 951b05f

Browse files
authored
Merge pull request #7360 from neshkeev/wip/7359-fix-sam-processing
Fixes #7359 - Fix SAM processing
2 parents 87ea7a6 + f183cc0 commit 951b05f

21 files changed

+269
-5
lines changed

compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
846846
def addRemoteRemoteExceptionAnnotation: Unit = ()
847847

848848
def samMethod(): Symbol = ctx.atPhase(ctx.erasurePhase) {
849-
toDenot(sym).info.abstractTermMembers.toList match {
849+
val samMethods = toDenot(sym).info.possibleSamMethods.toList
850+
samMethods match {
850851
case x :: Nil => x.symbol
851852
case Nil => abort(s"${sym.show} is not a functional interface. It doesn't have abstract methods")
852853
case xs => abort(s"${sym.show} is not a functional interface. " +

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import java.lang.ref.WeakReference
3737
import scala.annotation.internal.sharable
3838
import scala.annotation.threadUnsafe
3939

40+
import dotty.tools.dotc.transform.SymUtils._
41+
4042
object Types {
4143

4244
@sharable private var nextId = 0
@@ -767,6 +769,26 @@ object Types {
767769
(name, buf) => buf ++= nonPrivateMember(name).altsWith(_.is(Deferred)))
768770
}
769771

772+
/**
773+
* Returns the set of methods that are abstract and do not overlap with any of
774+
* [[java.lang.Object]] methods.
775+
*
776+
* Conceptually, a SAM (functional interface) has exactly one abstract method.
777+
* If an interface declares an abstract method overriding one of the public
778+
* methods of [[java.lang.Object]], that also does not count toward the interface's
779+
* abstract method count.
780+
*
781+
* @see https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
782+
*
783+
* @return the set of methods that are abstract and do not match any of [[java.lang.Object]]
784+
*
785+
*/
786+
final def possibleSamMethods(implicit ctx: Context): Seq[SingleDenotation] = {
787+
record("possibleSamMethods")
788+
abstractTermMembers
789+
.filterNot(m => m.symbol.matchingMember(defn.ObjectType).exists || m.symbol.isSuperAccessor)
790+
}
791+
770792
/** The set of abstract type members of this type. */
771793
final def abstractTypeMembers(implicit ctx: Context): Seq[SingleDenotation] = {
772794
record("abstractTypeMembers")
@@ -4369,8 +4391,7 @@ object Types {
43694391
}
43704392
def unapply(tp: Type)(implicit ctx: Context): Option[MethodType] =
43714393
if (isInstantiatable(tp)) {
4372-
val absMems = tp.abstractTermMembers
4373-
// println(s"absMems: ${absMems map (_.show) mkString ", "}")
4394+
val absMems = tp.possibleSamMethods
43744395
if (absMems.size == 1)
43754396
absMems.head.info match {
43764397
case mt: MethodType if !mt.isParamDependent &&

compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ExpandSAMs extends MiniPhase {
4646
tree
4747
case tpe =>
4848
val tpe1 = checkRefinements(tpe, fn)
49-
val Seq(samDenot) = tpe1.abstractTermMembers.filter(!_.symbol.isSuperAccessor)
49+
val Seq(samDenot) = tpe1.possibleSamMethods
5050
cpy.Block(tree)(stats,
5151
AnonClass(tpe1 :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil))
5252
}

project/Build.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ object Build {
979979
++ (dir / "shared/src/test/scala/org/scalajs/testsuite/niobuffer" ** (("*.scala": FileFilter) -- "ByteBufferTest.scala")).get
980980
++ (dir / "shared/src/test/scala/org/scalajs/testsuite/niocharset" ** (("*.scala": FileFilter) -- "BaseCharsetTest.scala" -- "Latin1Test.scala" -- "USASCIITest.scala" -- "UTF16Test.scala" -- "UTF8Test.scala")).get
981981
++ (dir / "shared/src/test/scala/org/scalajs/testsuite/scalalib" ** (("*.scala": FileFilter) -- "ArrayBuilderTest.scala" -- "ClassTagTest.scala" -- "EnumerationTest.scala" -- "RangesTest.scala" -- "SymbolTest.scala")).get
982-
++ (dir / "shared/src/test/require-sam" ** (("*.scala": FileFilter) -- "SAMTest.scala")).get
982+
++ (dir / "shared/src/test/require-sam" ** "*.scala").get
983983
++ (dir / "shared/src/test/require-jdk8/org/scalajs/testsuite/compiler" ** (("*.scala": FileFilter) -- "DefaultMethodsTest.scala")).get
984984
++ (dir / "shared/src/test/require-jdk8/org/scalajs/testsuite/javalib/lang" ** "*.scala").get
985985
++ (dir / "shared/src/test/require-jdk8/org/scalajs/testsuite/javalib/util" ** (("*.scala": FileFilter) -- "CollectionsOnCopyOnWriteArrayListTestOnJDK8.scala")).get

tests/neg/i7359-b.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E105] Syntax Error: tests/neg/i7359-b.scala:3:6 --------------------------------------------------------------------
2+
3 | def notifyAll(): Unit // error
3+
| ^
4+
| Traits cannot redefine final method notifyAll from class AnyRef.

tests/neg/i7359-b.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait SAMTrait
2+
def first(): String
3+
def notifyAll(): Unit // error

tests/neg/i7359-c.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E105] Syntax Error: tests/neg/i7359-c.scala:3:6 --------------------------------------------------------------------
2+
3 | def wait(): Unit // error
3+
| ^
4+
| Traits cannot redefine final method wait from class AnyRef.

tests/neg/i7359-c.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait SAMTrait
2+
def first(): String
3+
def wait(): Unit // error

tests/neg/i7359-d.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E105] Syntax Error: tests/neg/i7359-d.scala:3:6 --------------------------------------------------------------------
2+
3 | def wait(a: Long): Unit // error
3+
| ^
4+
| Traits cannot redefine final method wait from class AnyRef.

tests/neg/i7359-d.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait SAMTrait
2+
def first(): String
3+
def wait(a: Long): Unit // error

0 commit comments

Comments
 (0)