aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala2
-rw-r--r--src/dotty/tools/dotc/transform/ExpandSAMs.scala20
-rw-r--r--tests/pos/sams.scala12
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