diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2013-10-14 07:16:34 -0700 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2013-10-14 07:16:34 -0700 |
commit | 686fb483e721ba2bef77e185afd5bf97a134d890 (patch) | |
tree | 75200d850cf9b39ec979e8eea71e1a2a6dbb7946 /src/reflect | |
parent | d068b163d36b3fbffe39f87e3dc152a14c3ca07e (diff) | |
parent | b126e5c31b2bc57df5d0d5cf3508babe1dd7a759 (diff) | |
download | scala-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.scala | 39 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 22 |
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 } |