From a2ad291acd159ed299eb30305e42a0bace95f02a Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 20 May 2013 21:56:14 -0700 Subject: 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. --- src/reflect/scala/reflect/internal/Symbols.scala | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'src/reflect') 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 } -- cgit v1.2.3