diff options
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ExpandSAMs.scala | 20 | ||||
-rw-r--r-- | tests/pos/sams.scala | 12 |
3 files changed, 28 insertions, 6 deletions
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index f62c3cae8..7435f0baf 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -332,7 +332,7 @@ object Flags { final val JavaStaticTerm = JavaStatic.toTermFlags final val JavaStaticType = JavaStatic.toTypeFlags - /** Trait is not an interface, but does not have fields or initialization code */ + /** Trait does not have fields or initialization code */ final val NoInits = typeFlag(32, "<noInits>") /** Variable is accessed from nested function. */ diff --git a/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 3b151dc31..bba42f403 100644 --- a/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -5,15 +5,19 @@ import core._ import Contexts._, Symbols._, Types._, Flags._, Decorators._, StdNames._, Constants._ import SymDenotations.SymDenotation import TreeTransforms._ +import SymUtils._ import ast.untpd import ast.Trees._ -/** Expand SAM closures that cannot be represented by the JVM to anonymous classes. - * These fall into three categories +/** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes. + * These fall into five categories * * 1. Partial function closures, we need to generate a isDefinedAt method for these. - * 2. Closures implementaing non-trait classes. - * 3. Closures that get synthesized abstract methods in the transformation pipeline. These methods can be + * 2. Closures implementing non-trait classes. + * 3. Closures implementing classes that inherit from a class other than Object + * (a lambda cannot not be a run-time subtype of such a class) + * 4. Closures that implement traits which run initialization code. + * 5. Closures that get synthesized abstract methods in the transformation pipeline. These methods can be * (1) superaccessors, (2) outer references, (3) accessors for fields. */ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => @@ -22,7 +26,13 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => import ast.tpd._ def noJvmSam(cls: ClassSymbol)(implicit ctx: Context): Boolean = - !cls.is(Trait) || ExplicitOuter.needsOuterIfReferenced(cls) || cls.typeRef.fields.nonEmpty + !cls.is(Trait) || + cls.superClass != defn.ObjectClass || + !cls.is(NoInits) || + !cls.directlyInheritedTraits.forall(_.is(NoInits)) || + ExplicitOuter.needsOuterIfReferenced(cls) || + cls.typeRef.fields.nonEmpty // Superaccessors already show up as abstract methods here, so no test necessary + override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree = tree match { case Block(stats @ (fn: DefDef) :: Nil, Closure(_, fnRef, tpt)) if fnRef.symbol == fn.symbol => diff --git a/tests/pos/sams.scala b/tests/pos/sams.scala index 671213fef..b7ef7dd2d 100644 --- a/tests/pos/sams.scala +++ b/tests/pos/sams.scala @@ -15,12 +15,24 @@ object test { val u: U = (x: Int) => 2 // needs to be an anonymous class because of inherited field + trait V extends Exception { def foo(x: Int): Int } + + val v: V = (x: Int) => 2 // needs to be an anonymous class because the trait extends a non-object class + trait Y extends X { def baz = super.bar } val y: Y = (x: Int) => 2 // needs to be an anonymous class because of super accessor + trait Z { + def foo(x: Int): Int; println("hi there!") + } + trait ZZ extends Z + + val z: Z = (x: Int) => 2 // needs to be an anonymous class because trait has initialization code + val zz: ZZ = (x: Int) => 2 // needs to be an anonymous class becaiuse trait has initialization code + abstract class C { def foo(x: Int): Int |