From f922f367d58b3ba6bbb4cb0864ce82c5cd6f7966 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 17 Mar 2016 11:56:14 -0700 Subject: Additional SAM restrictions identified by Jason Also test roundtripping serialization of a lambda that targets a SAM that's not FunctionN (it should make no difference). --- .../scala/reflect/internal/Definitions.scala | 25 ++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 2fa39bc453..ef9a76f9c4 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -844,13 +844,26 @@ trait Definitions extends api.StandardDefinitions { * has a public no-arg primary constructor. */ def samOf(tp: Type): Symbol = { - // if tp has a constructor, it must be public and must not take any arguments - // (not even an implicit argument list -- to keep it simple for now) - val tpSym = tp.typeSymbol - val ctor = tpSym.primaryConstructor - val ctorOk = !ctor.exists || (!ctor.isOverloaded && ctor.isPublic && ctor.info.params.isEmpty && ctor.info.paramSectionCount <= 1) + // look at erased type because we (only) care about what ends up in bytecode + // (e.g., an alias type or intersection type is fine as long as the intersection dominator compiles to an interface) + val tpSym = erasure.javaErasure(tp).typeSymbol + + if (tpSym.exists + // We use Java's MetaLambdaFactory, which requires an interface for the sam's owner + // (TODO: Can't use isInterface, yet, as it hasn't been updated for the new trait encoding) + && (tpSym.isJavaInterface || tpSym.isTrait) + // explicit outer precludes no-arg ctor + && tpSym.isStatic + // impl restriction -- we currently use the boxed apply, so not really useful to allow specialized sam types (https://github.com/scala/scala/pull/4971#issuecomment-198119167) + && !tpSym.isSpecialized) { + + // this does not apply yet, since traits don't have constructors during type checking + // if tp has a constructor, it must be public and must not take any arguments + // (not even an implicit argument list -- to keep it simple for now) + // && { val ctor = tpSym.primaryConstructor + // !ctor.exists || (!ctor.isOverloaded && ctor.isPublic && ctor.info.params.isEmpty && ctor.info.paramSectionCount <= 1) + // } - if (tpSym.exists && ctorOk) { // find the single abstract member, if there is one // don't go out requiring DEFERRED members, as you will get them even if there's a concrete override: // scala> abstract class X { def m: Int } -- cgit v1.2.3