Skip to content

Commit 37098b1

Browse files
committed
Rework isBottomType
Now uses a new method hasClassSymbol instead of recursively calling derivesFrom.
1 parent 51f67b4 commit 37098b1

File tree

2 files changed

+31
-17
lines changed

2 files changed

+31
-17
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,13 +1175,11 @@ class Definitions {
11751175
def isBottomClassAfterErasure(cls: Symbol): Boolean = cls == NothingClass || cls == NullClass
11761176

11771177
def isBottomType(tp: Type): Boolean =
1178-
val tpw = tp.widen
1179-
tpw.isCombinedRef(NothingClass)
1180-
|| tpw.isCombinedRef(NullClass) && (!ctx.explicitNulls || ctx.phase.erasedTypes)
1178+
if ctx.explicitNulls && !ctx.phase.erasedTypes then tp.hasClassSymbol(NothingClass)
1179+
else isBottomTypeAfterErasure(tp)
11811180

11821181
def isBottomTypeAfterErasure(tp: Type): Boolean =
1183-
val tpw = tp.widen
1184-
tpw.isCombinedRef(NothingClass) || tpw.isCombinedRef(NullClass)
1182+
tp.hasClassSymbol(NothingClass) || tp.hasClassSymbol(NullClass)
11851183

11861184
/** Is a function class.
11871185
* - FunctionXXL

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,6 @@ object Types {
205205
false
206206
}
207207

208-
/** Like isRef, but also extends to unions and intersections */
209-
def isCombinedRef(sym: Symbol)(using Context): Boolean = stripped match
210-
case AndType(tp1: Type, tp2: Type) => tp1.isRef(sym) || tp2.isRef(sym)
211-
case OrType(tp1: Type, tp2: Type) => tp1.isRef(sym) && tp2.isRef(sym)
212-
case _ => isRef(sym)
213-
214208
def isAny(using Context): Boolean = isRef(defn.AnyClass, skipRefined = false)
215209
def isAnyRef(using Context): Boolean = isRef(defn.ObjectClass, skipRefined = false)
216210
def isAnyKind(using Context): Boolean = isRef(defn.AnyKindClass, skipRefined = false)
@@ -230,7 +224,9 @@ object Types {
230224
case _ => false
231225
}
232226

233-
/** Is this type an instance of a non-bottom subclass of the given class `cls`? */
227+
/** True if this type is an instance of the given `cls` or an instance of
228+
* a non-bottom subclass of `cls`.
229+
*/
234230
final def derivesFrom(cls: Symbol)(using Context): Boolean = {
235231
def loop(tp: Type): Boolean = tp match {
236232
case tp: TypeRef =>
@@ -245,11 +241,15 @@ object Types {
245241
case tp: AndType =>
246242
loop(tp.tp1) || loop(tp.tp2)
247243
case tp: OrType =>
248-
// If the type is `T | Null` or `T | Nothing`, and `T` derivesFrom the class,
249-
// then the OrType derivesFrom the class. Otherwise, we need to check both sides
250-
// derivesFrom the class.
251-
loop(tp.tp1) && (loop(tp.tp2) || defn.isBottomType(tp.tp2))
252-
|| defn.isBottomType(tp.tp1) && loop(tp.tp2)
244+
// If the type is `T | Null` or `T | Nothing`, the class is != Nothing,
245+
// and `T` derivesFrom the class, then the OrType derivesFrom the class.
246+
// Otherwise, we need to check both sides derivesFrom the class.
247+
if defn.isBottomType(tp.tp1) && cls != defn.NothingClass then
248+
loop(tp.tp2)
249+
else if defn.isBottomType(tp.tp2) && cls != defn.NothingClass then
250+
loop(tp.tp1)
251+
else
252+
loop(tp.tp1) && loop(tp.tp2)
253253
case tp: JavaArrayType =>
254254
cls == defn.ObjectClass
255255
case _ =>
@@ -484,6 +484,22 @@ object Types {
484484
final def classSymbols(using Context): List[ClassSymbol] =
485485
parentSymbols(_.isClass).asInstanceOf
486486

487+
/** Same as `this.classSymbols.contains(cls)` but more efficient */
488+
final def hasClassSymbol(cls: Symbol)(using Context): Boolean = this match
489+
case tp: TypeRef =>
490+
val sym = tp.symbol
491+
sym == cls || !sym.isClass && tp.superType.hasClassSymbol(cls)
492+
case tp: TypeProxy =>
493+
tp.underlying.hasClassSymbol(cls)
494+
case tp: ClassInfo =>
495+
tp.cls == cls
496+
case AndType(l, r) =>
497+
l.hasClassSymbol(cls) || r.hasClassSymbol(cls)
498+
case OrType(l, r) =>
499+
l.hasClassSymbol(cls) && r.hasClassSymbol(cls)
500+
case _ =>
501+
false
502+
487503
/** The term symbol associated with the type */
488504
@tailrec final def termSymbol(using Context): Symbol = this match {
489505
case tp: TermRef => tp.symbol

0 commit comments

Comments
 (0)