summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/Symbols.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-05-20 21:56:14 -0700
committerPaul Phillips <paulp@improving.org>2013-05-21 01:18:20 -0700
commita2ad291acd159ed299eb30305e42a0bace95f02a (patch)
tree63dc189dea7b1096232da0a4e0d0edfdf676578f /src/reflect/scala/reflect/internal/Symbols.scala
parent085b4d9bdb7ba9f9fe00c63e998e93278a34b161 (diff)
downloadscala-a2ad291acd159ed299eb30305e42a0bace95f02a.tar.gz
scala-a2ad291acd159ed299eb30305e42a0bace95f02a.tar.bz2
scala-a2ad291acd159ed299eb30305e42a0bace95f02a.zip
SI-3425 erasure crash with refinement members.
Checking that a refinement class symbol does not override any symbols does mean it will have to be invoke reflectively; but the converse is not true. It can override other symbols and still have to be called reflectively, because the overridden symbols may also be defined in refinement classes. scala> class Foo { type R1 <: { def x: Any } ; type R2 <: R1 { def x: Int } } defined class Foo scala> typeOf[Foo].member(TypeName("R2")).info.member("x": TermName).overrideChain res1: List[$r.intp.global.Symbol] = List(method x, method x) scala> res1 filterNot (_.owner.isRefinementClass) res2: List[$r.intp.global.Symbol] = List() And checking that "owner.info decl name == this" only works if name is not overloaded. So the logic is all in "isOnlyRefinementMember" now, and let's hope that suffices for a while.
Diffstat (limited to 'src/reflect/scala/reflect/internal/Symbols.scala')
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala23
1 files changed, 15 insertions, 8 deletions
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index af20b8b756..8343ae6b07 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -892,16 +892,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Is this a term symbol only defined in a refinement (so that it needs
* to be accessed by reflection)?
*/
- def isOnlyRefinementMember: Boolean = (
- isTerm && // type members are not affected
- owner.isRefinementClass && // owner must be a refinement class
- (owner.info decl name) == this && // symbol must be explicitly declared in the refinement (not synthesized from glb)
- !isOverridingSymbol && // symbol must not override a symbol in a base class
- !isConstant // symbol must not be a constant. Question: Can we exclude @inline methods as well?
+ def isOnlyRefinementMember = (
+ isTerm // Type members are unaffected
+ && owner.isRefinementClass // owner must be a refinement class
+ && isPossibleInRefinement // any overridden symbols must also have refinement class owners
+ && !isConstant // Must not be a constant. Question: Can we exclude @inline methods as well?
+ && isDeclaredByOwner // Must be explicitly declared in the refinement (not synthesized from glb)
)
+ // "(owner.info decl name) == this" is inadequate, because "name" might
+ // be overloaded in owner - and this might be an overloaded symbol.
+ // TODO - make this cheaper and see where else we should be doing something similar.
+ private def isDeclaredByOwner = (owner.info decl name).alternatives exists (alternatives contains _)
final def isStructuralRefinementMember = owner.isStructuralRefinement && isPossibleInRefinement && isPublic
- final def isPossibleInRefinement = !isConstructor && !isOverridingSymbol
+ final def isPossibleInRefinement = (
+ !isConstructor
+ && allOverriddenSymbols.forall(_.owner.isRefinementClass) // this includes allOverriddenSymbols.isEmpty
+ )
/** A a member of class `base` is incomplete if
* (1) it is declared deferred or
@@ -3430,7 +3437,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
@tailrec private[scala] final
def allSymbolsHaveOwner(syms: List[Symbol], owner: Symbol): Boolean = syms match {
case sym :: rest => sym.owner == owner && allSymbolsHaveOwner(rest, owner)
- case _ => true
+ case _ => true
}