diff options
author | Paul Phillips <paulp@improving.org> | 2013-03-13 16:09:33 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-03-13 16:18:01 -0700 |
commit | 4f17806b1d3b0e6fb66a387b74ee9ea15da77ed8 (patch) | |
tree | 1b88dcb05917904d3c4d317763660903c64b6432 /src/reflect | |
parent | a063bb020f2b965b0356491b08c04be0f308872b (diff) | |
download | scala-4f17806b1d3b0e6fb66a387b74ee9ea15da77ed8.tar.gz scala-4f17806b1d3b0e6fb66a387b74ee9ea15da77ed8.tar.bz2 scala-4f17806b1d3b0e6fb66a387b74ee9ea15da77ed8.zip |
Eliminated containsNull.
This was a little trickier than the previous. I introduced
a new method 'isBottomSubClass' which is the obvious complement
to the beloved 'isNonBottomSubClass'. In eliminating the two
call sites of containsNull I might have overshot the mark a
bit when I rewrote fourthTry and thirdTryRef, but who is going
to argue with such beauty as this.
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/Symbols.scala | 13 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 31 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/tpe/TypeComparers.scala | 122 |
3 files changed, 85 insertions, 81 deletions
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 6837f37445..c881de7830 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -1671,6 +1671,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => * and is this class symbol also different from Null or Nothing? */ def isNonBottomSubClass(that: Symbol): Boolean = false + /** Is this class symbol Null or Nothing, + * and (if Null) is `that` inhabited by null? + * If this is Nothing, of course, it is a + * subclass of `that` by definition. + * + * TODO - what is implied by the fact that AnyVal now has + * infinitely many non-bottom subclasses, not only 9? + */ + def isBottomSubClass(that: Symbol) = ( + (this eq NothingClass) + || (this eq NullClass) && that.isClass && (that ne NothingClass) && !(that isNonBottomSubClass AnyValClass) + ) + /** Overridden in NullClass and NothingClass for custom behavior. */ def isSubClass(that: Symbol) = isNonBottomSubClass(that) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 5d2ea1d97f..a678edbe01 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -4051,23 +4051,22 @@ trait Types corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg) } - protected[internal] def containsNull(sym: Symbol): Boolean = - sym.isClass && sym != NothingClass && - !(sym isNonBottomSubClass AnyValClass) - - def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean = - tp.typeSymbol == NothingClass || - tp.typeSymbol == NullClass && containsNull(sym.owner) || { - def specializedBy(membr: Symbol): Boolean = - membr == sym || specializesSym(tp.narrow, membr, sym.owner.thisType, sym, depth) - val member = tp.nonPrivateMember(sym.name) + def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean = { + def directlySpecializedBy(member: Symbol): Boolean = ( + member == sym + || specializesSym(tp.narrow, member, sym.owner.thisType, sym, depth) + ) + // Closure reduction, else this would be simply `member exists directlySpecializedBy` + def specializedBy(member: Symbol): Boolean = ( if (member eq NoSymbol) false - else if (member.isOverloaded) member.alternatives exists specializedBy - else specializedBy(member) - // was - // (tp.nonPrivateMember(sym.name).alternatives exists - // (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth))) - } + else if (member.isOverloaded) member.alternatives exists directlySpecializedBy + else directlySpecializedBy(member) + ) + + ( (tp.typeSymbol isBottomSubClass sym.owner) + || specializedBy(tp nonPrivateMember sym.name) + ) + } /** Does member `sym1` of `tp1` have a stronger type * than member `sym2` of `tp2`? diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index 863d2109df..d36aa0c927 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -74,14 +74,17 @@ trait TypeComparers { // if (subsametypeRecursions == 0) undoLog.clear() } - def isDifferentTypeConstructor(tp1: Type, tp2: Type): Boolean = tp1 match { - case TypeRef(pre1, sym1, _) => - tp2 match { - case TypeRef(pre2, sym2, _) => sym1 != sym2 || isDifferentType(pre1, pre2) - case _ => true - } - case _ => true - } + def isDifferentTypeConstructor(tp1: Type, tp2: Type) = !isSameTypeConstructor(tp1, tp2) + + private def isSameTypeConstructor(tr1: TypeRef, tr2: TypeRef): Boolean = ( + (tr1.sym == tr2.sym) + && !isDifferentType(tr1.pre, tr2.pre) + ) + private def isSameTypeConstructor(tp1: Type, tp2: Type): Boolean = ( + tp1.isInstanceOf[TypeRef] + && tp2.isInstanceOf[TypeRef] + && isSameTypeConstructor(tp1.asInstanceOf[TypeRef], tp2.asInstanceOf[TypeRef]) + ) /** Do `tp1` and `tp2` denote equivalent types? */ def isSameType(tp1: Type, tp2: Type): Boolean = try { @@ -403,6 +406,9 @@ trait TypeComparers { case tr2: TypeRef => tp1 match { case tr1: TypeRef => + // TODO - dedicate a method to TypeRef/TypeRef subtyping. + // These typerefs are pattern matched up and down far more + // than is necessary. val sym1 = tr1.sym val sym2 = tr2.sym val pre1 = tr1.pre @@ -465,26 +471,19 @@ trait TypeComparers { def thirdTryRef(tp1: Type, tp2: TypeRef): Boolean = { val sym2 = tp2.sym + def retry(lhs: Type, rhs: Type) = isSubType(lhs, rhs, depth) + def abstractTypeOnRight(lo: Type) = isDifferentTypeConstructor(tp2, lo) && retry(tp1, lo) + def classOnRight = ( + if (isRawType(tp2)) retry(tp1, rawToExistential(tp2)) + else if (sym2.isRefinementClass) retry(tp1, sym2.info) + else fourthTry + ) sym2 match { - case SingletonClass => tp1.isStable || fourthTry - case _: ClassSymbol => - if (isRawType(tp2)) - isSubType(tp1, rawToExistential(tp2), depth) - else if (sym2.name == tpnme.REFINE_CLASS_NAME) - isSubType(tp1, sym2.info, depth) - else - fourthTry - case _: TypeSymbol => - if (sym2 hasFlag DEFERRED) { - val tp2a = tp2.bounds.lo - isDifferentTypeConstructor(tp2, tp2a) && - isSubType(tp1, tp2a, depth) || - fourthTry - } else { - isSubType(tp1.normalize, tp2.normalize, depth) - } - case _ => - fourthTry + case SingletonClass => tp1.isStable || fourthTry + case _: ClassSymbol => classOnRight + case _: TypeSymbol if sym2.isDeferred => abstractTypeOnRight(tp2.bounds.lo) || fourthTry + case _: TypeSymbol => retry(tp1.normalize, tp2.normalize) + case _ => fourthTry } } @@ -536,44 +535,37 @@ trait TypeComparers { /** Fourth try, on the left: * - handle typerefs, refined types, and singleton types. */ - def fourthTry = tp1 match { - case tr1 @ TypeRef(pre1, sym1, _) => - sym1 match { - case NothingClass => true - case NullClass => - tp2 match { - case TypeRef(_, sym2, _) => - containsNull(sym2) - case _ => - isSingleType(tp2) && isSubType(tp1, tp2.widen, depth) - } - case _: ClassSymbol => - if (isRawType(tp1)) - isSubType(rawToExistential(tp1), tp2, depth) - else if (sym1.isModuleClass) tp2 match { - case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2) - case _ => false - } - else if (sym1.isRefinementClass) - isSubType(sym1.info, tp2, depth) - else false - - case _: TypeSymbol => - if (sym1 hasFlag DEFERRED) { - val tp1a = tp1.bounds.hi - isDifferentTypeConstructor(tp1, tp1a) && isSubType(tp1a, tp2, depth) - } else { - isSubType(tp1.normalize, tp2.normalize, depth) - } - case _ => - false - } - case RefinedType(parents1, _) => - parents1 exists (isSubType(_, tp2, depth)) - case _: SingletonType => - isSubType(tp1.underlying, tp2, depth) - case _ => - false + def fourthTry = { + def retry(lhs: Type, rhs: Type) = isSubType(lhs, rhs, depth) + def abstractTypeOnLeft(hi: Type) = isDifferentTypeConstructor(tp1, hi) && retry(hi, tp2) + + tp1 match { + case tr1 @ TypeRef(pre1, sym1, _) => + def nullOnLeft = tp2 match { + case TypeRef(_, sym2, _) => sym1 isBottomSubClass sym2 + case _ => isSingleType(tp2) && retry(tp1, tp2.widen) + } + def moduleOnLeft = tp2 match { + case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2) + case _ => false + } + def classOnLeft = ( + if (isRawType(tp1)) retry(rawToExistential(tp1), tp2) + else if (sym1.isModuleClass) moduleOnLeft + else sym1.isRefinementClass && retry(sym1.info, tp2) + ) + sym1 match { + case NothingClass => true + case NullClass => nullOnLeft + case _: ClassSymbol => classOnLeft + case _: TypeSymbol if sym1.isDeferred => abstractTypeOnLeft(tp1.bounds.hi) + case _: TypeSymbol => retry(tp1.normalize, tp2.normalize) + case _ => false + } + case RefinedType(parents, _) => parents exists (retry(_, tp2)) + case _: SingletonType => retry(tp1.underlying, tp2) + case _ => false + } } firstTry |