summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2013-10-14 07:16:34 -0700
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2013-10-14 07:16:34 -0700
commit686fb483e721ba2bef77e185afd5bf97a134d890 (patch)
tree75200d850cf9b39ec979e8eea71e1a2a6dbb7946 /src/reflect
parentd068b163d36b3fbffe39f87e3dc152a14c3ca07e (diff)
parentb126e5c31b2bc57df5d0d5cf3508babe1dd7a759 (diff)
downloadscala-686fb483e721ba2bef77e185afd5bf97a134d890.tar.gz
scala-686fb483e721ba2bef77e185afd5bf97a134d890.tar.bz2
scala-686fb483e721ba2bef77e185afd5bf97a134d890.zip
Merge pull request #3037 from gkossakowski/fix-merge-3018v2.11.0-M6
[resubmit] Experimental Single Abstract Method support (sammy meets world)
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala39
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala22
2 files changed, 56 insertions, 5 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 4d8ae73bcc..99aad4f057 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -799,6 +799,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.isDeferredNotDefault && !isUniversalMember(mem)) // TODO: test
+ )
+
+ // 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)
@@ -1089,6 +1127,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val ScalaInlineClass = requiredClass[scala.inline]
lazy val ScalaNoInlineClass = requiredClass[scala.noinline]
lazy val SerialVersionUIDAttr = requiredClass[scala.SerialVersionUID]
+ lazy val SerialVersionUIDAnnotation = AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List())
lazy val SpecializedClass = requiredClass[scala.specialized]
lazy val ThrowsClass = requiredClass[scala.throws[_]]
lazy val TransientAttr = requiredClass[scala.transient]
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 85dfa037ec..8f19e89dd4 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -974,6 +974,18 @@ trait Types
else (baseClasses.head.newOverloaded(this, alts))
}
+ /** Find all members meeting the flag requirements.
+ *
+ * If you require a DEFERRED member, you will get it if it exists -- even if there's an overriding concrete member.
+ * If you exclude DEFERRED members, or don't specify any requirements,
+ * you won't get deferred members (whether they have an overriding concrete member or not)
+ *
+ * Thus, findMember requiring DEFERRED flags yields deferred members,
+ * while `findMember(excludedFlags = 0, requiredFlags = 0).filter(_.isDeferred)` may not (if there's a corresponding concrete member)
+ *
+ * Requirements take precedence over exclusions, so requiring and excluding DEFERRED will yield a DEFERRED member (if there is one).
+ *
+ */
def findMembers(excludedFlags: Long, requiredFlags: Long): Scope = {
def findMembersInternal: Scope = {
var members: Scope = null
@@ -983,10 +995,10 @@ trait Types
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var required = requiredFlags
var excluded = excludedFlags | DEFERRED
- var continue = true
+ var retryForDeferred = true
var self: Type = null
- while (continue) {
- continue = false
+ while (retryForDeferred) {
+ retryForDeferred = false
val bcs0 = baseClasses
var bcs = bcs0
while (!bcs.isEmpty) {
@@ -1018,7 +1030,7 @@ trait Types
}
if (others eq null) members enter sym
} else if (excl == DEFERRED) {
- continue = true
+ retryForDeferred = (excludedFlags & DEFERRED) == 0
}
}
entry = entry.next
@@ -1028,7 +1040,7 @@ trait Types
} // while (!bcs.isEmpty)
required |= DEFERRED
excluded &= ~(DEFERRED.toLong)
- } // while (continue)
+ } // while (retryForDeferred)
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
if (members eq null) EmptyScope else members
}