summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2013-10-03 22:04:59 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-10-04 10:55:11 -0700
commit657e85fe2412cdadc5ee9dc348159b32dcdfcba7 (patch)
tree28738fe4f1870a47e06c505d073f52567e8d29ab /src/reflect
parente864129a7e7f01d76e177d1bba46d54aea39368e (diff)
downloadscala-657e85fe2412cdadc5ee9dc348159b32dcdfcba7.tar.gz
scala-657e85fe2412cdadc5ee9dc348159b32dcdfcba7.tar.bz2
scala-657e85fe2412cdadc5ee9dc348159b32dcdfcba7.zip
Single Abstract Method support: synthesis helpers
`synthesizeSAMFunction` will be used to expand the following tree: ``` { (p1: T1, ..., pN: TN) => body } : S ``` to: ``` { def apply$body(p1: T1, ..., pN: TN): T = body new S { def apply(p1: T1, ..., pN: TN): T = apply$body(p1,..., pN) } } ``` The expansion assumes `S` (the expected type) defines a single abstract method (let's call that method `apply` for simplicity). 1. If 'T' is not fully defined, it is inferred by type checking `def apply$body` without a result type before type checking the block. The method's inferred result type is used instead of T`. [See test/files/pos/sammy_poly.scala] 2. To more easily enforce S's members are not in scope in `body`, that tree goes to the `apply$body` method that's outside the anonymous subclass of S. (The separate `apply$body` method simplifies the implementation of 1&2.) 3. The following restrictions apply to S: 1. Its primary constructor (if any) must be public, no-args, not overloaded. 2. S must have exactly one abstract member, its SAM 3. SAM must take exactly one argument list 4. SAM must be monomorphic We may later relax these requirements to allow an implicit argument list, both on the constructor and the SAM. Could also let the SAM be polymorphic.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 7b2e40b59c..6fb99b9a5b 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -724,6 +724,44 @@ trait Definitions extends api.StandardDefinitions {
(sym eq PartialFunctionClass) || (sym eq AbstractPartialFunctionClass)
}
+ /** The single abstract method declared by type `tp` (or `NoSymbol` if it cannot be found).
+ *
+ * The method must be monomorphic and have exactly one parameter list.
+ * The class defining the method is a supertype of `tp` that
+ * 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)
+
+ 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 }
+ // scala> class Y extends X { def m: Int = 1}
+ // scala> typeOf[Y].deferredMembers
+ // Scopes(method m, method getClass)
+ //
+ // scala> typeOf[Y].members.filter(_.isDeferred)
+ // Scopes()
+ // must filter out "universal" members (getClass is deferred for some reason)
+ val deferredMembers = (
+ tp membersBasedOnFlags (excludedFlags = BridgeAndPrivateFlags, requiredFlags = METHOD)
+ filter (mem => mem.isDeferred && !isUniversalMember(mem))
+ )
+
+ // if there is only one, it's monomorphic and has a single argument list
+ if (deferredMembers.size == 1 &&
+ deferredMembers.head.typeParams.isEmpty &&
+ deferredMembers.head.info.paramSectionCount == 1)
+ deferredMembers.head
+ else NoSymbol
+ } else NoSymbol
+ }
+
def arrayType(arg: Type) = appliedType(ArrayClass, arg)
def byNameType(arg: Type) = appliedType(ByNameParamClass, arg)
def iteratorOfType(tp: Type) = appliedType(IteratorClass, tp)