Skip to content

Commit ca8f97f

Browse files
committed
More precise check for Any/Nothing, ruling out singleton types
SingletonTypes can have Any as their typeSymbol, confusing kinding and bounds checking logic. Prior to this commit there were several places where it was assumed that tpe.typeSymbol(Direct) == AnyClass tells us that tpe is Any. This confused bounds and kind checking in circumstances which arise where singleton types of values of subtypes Any are expressible (ie. via literal types) because these SingleTypes delegate typeSymbol(Direct) to their underlying, which is Any. Mutatis mutandis for Nothing. The various instances of these tests have been consolidated under typeIsAny and typeIsNothing in Types. In addition these have been changed from function values to methods to improve performance.
1 parent c7de0eb commit ca8f97f

File tree

3 files changed

+38
-12
lines changed

3 files changed

+38
-12
lines changed

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3252,12 +3252,14 @@ trait Types
32523252
* }}}
32533253
*/
32543254
def unifySimple = {
3255-
val sym = tp.typeSymbol
3256-
if (sym == NothingClass || sym == AnyClass) { // kind-polymorphic
3257-
// scala/bug#7126 if we register some type alias `T=Any`, we can later end
3258-
// with malformed types like `T[T]` during type inference in
3259-
// `handlePolymorphicCall`. No such problem if we register `Any`.
3260-
addBound(sym.tpe)
3255+
// scala/bug#7126 if we register some type alias `T=Any`, we can later end
3256+
// with malformed types like `T[T]` during type inference in
3257+
// `handlePolymorphicCall`. No such problem if we register `Any`.
3258+
if (typeIsNothing(tp)) { // kind-polymorphic
3259+
addBound(NothingTpe)
3260+
true
3261+
} else if(typeIsAny(tp)) { // kind-polymorphic
3262+
addBound(AnyTpe)
32613263
true
32623264
} else if (params.isEmpty) {
32633265
addBound(tp)
@@ -4851,8 +4853,23 @@ trait Types
48514853
private[scala] val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp
48524854
private[scala] val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty
48534855
private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableTpe
4854-
private[scala] val typeIsNothing = (tp: Type) => tp.typeSymbolDirect eq NothingClass
4855-
private[scala] val typeIsAny = (tp: Type) => tp.typeSymbolDirect eq AnyClass
4856+
4857+
@tailrec
4858+
private[scala] final def typeIsNothing(tp: Type): Boolean =
4859+
tp.dealias match {
4860+
case PolyType(_, tp) => typeIsNothing(tp)
4861+
case TypeRef(_, NothingClass, _) => true
4862+
case _ => false
4863+
}
4864+
4865+
@tailrec
4866+
private[scala] final def typeIsAny(tp: Type): Boolean =
4867+
tp.dealias match {
4868+
case PolyType(_, tp) => typeIsAny(tp)
4869+
case TypeRef(_, AnyClass, _) => true
4870+
case _ => false
4871+
}
4872+
48564873
private[scala] val typeIsHigherKinded = (tp: Type) => tp.isHigherKinded
48574874

48584875
/** The maximum depth of type `tp` */

src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,7 @@ private[internal] trait TypeConstraints {
127127
def addHiBound(tp: Type, isNumericBound: Boolean = false) {
128128
// My current test case only demonstrates the need to let Nothing through as
129129
// a lower bound, but I suspect the situation is symmetrical.
130-
val mustConsider = tp.typeSymbol match {
131-
case AnyClass => true
132-
case _ => !(hibounds contains tp)
133-
}
130+
val mustConsider = typeIsAny(tp) || !(hibounds contains tp)
134131
if (mustConsider) {
135132
checkWidening(tp)
136133
if (isNumericBound && isNumericValueType(tp)) {

test/junit/scala/reflect/internal/TypesTest.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,16 @@ class TypesTest {
313313
assert(polyType(A => Bar(Int, A)) <:< _F && _F <:< polyType(A => Bar(Any, A)))
314314
}
315315
}
316+
317+
@Test
318+
def testAnyNothing(): Unit = {
319+
object Foo { val a: Any = 23 ; val n: Nothing = ??? }
320+
val aSym = typeOf[Foo.type].member(TermName("a"))
321+
val nSym = typeOf[Foo.type].member(TermName("n"))
322+
323+
assert(typeIsAny(AnyTpe))
324+
assert(typeIsNothing(NothingTpe))
325+
assert(!typeIsAny(SingleType(NoPrefix, aSym)))
326+
assert(!typeIsNothing(SingleType(NoPrefix, nSym)))
327+
}
316328
}

0 commit comments

Comments
 (0)