Skip to content

Commit dbe0456

Browse files
committed
More conditions under which SAMs are converted to anonymous classes
Also included are - Closures implementing classes that inherit from a class other than Object - Closures that implement traits which run initialization code.
1 parent 9be27ae commit dbe0456

File tree

3 files changed

+28
-6
lines changed

3 files changed

+28
-6
lines changed

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ object Flags {
332332
final val JavaStaticTerm = JavaStatic.toTermFlags
333333
final val JavaStaticType = JavaStatic.toTypeFlags
334334

335-
/** Trait is not an interface, but does not have fields or initialization code */
335+
/** Trait does not have fields or initialization code */
336336
final val NoInits = typeFlag(32, "<noInits>")
337337

338338
/** Variable is accessed from nested function. */

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@ import core._
55
import Contexts._, Symbols._, Types._, Flags._, Decorators._, StdNames._, Constants._
66
import SymDenotations.SymDenotation
77
import TreeTransforms._
8+
import SymUtils._
89
import ast.untpd
910
import ast.Trees._
1011

11-
/** Expand SAM closures that cannot be represented by the JVM to anonymous classes.
12-
* These fall into three categories
12+
/** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes.
13+
* These fall into five categories
1314
*
1415
* 1. Partial function closures, we need to generate a isDefinedAt method for these.
15-
* 2. Closures implementaing non-trait classes.
16-
* 3. Closures that get synthesized abstract methods in the transformation pipeline. These methods can be
16+
* 2. Closures implementing non-trait classes.
17+
* 3. Closures implementing classes that inherit from a class other than Object
18+
* (a lambda cannot not be a run-time subtype of such a class)
19+
* 4. Closures that implement traits which run initialization code.
20+
* 5. Closures that get synthesized abstract methods in the transformation pipeline. These methods can be
1721
* (1) superaccessors, (2) outer references, (3) accessors for fields.
1822
*/
1923
class ExpandSAMs extends MiniPhaseTransform { thisTransformer =>
@@ -22,7 +26,13 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer =>
2226
import ast.tpd._
2327

2428
def noJvmSam(cls: ClassSymbol)(implicit ctx: Context): Boolean =
25-
!cls.is(Trait) || ExplicitOuter.needsOuterIfReferenced(cls) || cls.typeRef.fields.nonEmpty
29+
!cls.is(Trait) ||
30+
cls.superClass != defn.ObjectClass ||
31+
!cls.is(NoInits) ||
32+
!cls.directlyInheritedTraits.forall(_.is(NoInits)) ||
33+
ExplicitOuter.needsOuterIfReferenced(cls) ||
34+
cls.typeRef.fields.nonEmpty // Superaccessors already show up as abstract methods here, so no test necessary
35+
2636

2737
override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree = tree match {
2838
case Block(stats @ (fn: DefDef) :: Nil, Closure(_, fnRef, tpt)) if fnRef.symbol == fn.symbol =>

tests/pos/sams.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,24 @@ object test {
1515

1616
val u: U = (x: Int) => 2 // needs to be an anonymous class because of inherited field
1717

18+
trait V extends Exception { def foo(x: Int): Int }
19+
20+
val v: V = (x: Int) => 2 // needs to be an anonymous class because the trait extends a non-object class
21+
1822
trait Y extends X {
1923
def baz = super.bar
2024
}
2125

2226
val y: Y = (x: Int) => 2 // needs to be an anonymous class because of super accessor
2327

28+
trait Z {
29+
def foo(x: Int): Int; println("hi there!")
30+
}
31+
trait ZZ extends Z
32+
33+
val z: Z = (x: Int) => 2 // needs to be an anonymous class because trait has initialization code
34+
val zz: ZZ = (x: Int) => 2 // needs to be an anonymous class becaiuse trait has initialization code
35+
2436
abstract class C {
2537
def foo(x: Int): Int
2638

0 commit comments

Comments
 (0)