Skip to content

Commit e6746e5

Browse files
committed
Special treatment of NotNull in TypeComparer
Makes use of the fact that `Null & NotNull = Nothing`. This fact is used in both type comparisons and glb operations.
1 parent 62b756b commit e6746e5

File tree

2 files changed

+43
-26
lines changed

2 files changed

+43
-26
lines changed

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

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
6262
private var myAnyKindClass: ClassSymbol = null
6363
private var myNothingClass: ClassSymbol = null
6464
private var myNullClass: ClassSymbol = null
65+
private var myNotNullClass: ClassSymbol = null
6566
private var myObjectClass: ClassSymbol = null
6667
private var myAnyType: TypeRef = null
6768
private var myAnyKindType: TypeRef = null
@@ -83,6 +84,10 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
8384
if (myNullClass == null) myNullClass = defn.NullClass
8485
myNullClass
8586
}
87+
def NotNullClass: ClassSymbol =
88+
if myNotNullClass == null then myNotNullClass = defn.NotNullClass
89+
myNotNullClass
90+
8691
def ObjectClass: ClassSymbol = {
8792
if (myObjectClass == null) myObjectClass = defn.ObjectClass
8893
myObjectClass
@@ -770,6 +775,15 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
770775
if (tp2a ne tp2) // Follow the alias; this might avoid truncating the search space in the either below
771776
return recur(tp1, tp2a)
772777

778+
if tp11.isRef(NotNullClass)
779+
tp12.widen match
780+
case OrNull(tp12a) if recur(tp12a, tp2) => return true
781+
case _ =>
782+
if tp12.isRef(NotNullClass)
783+
tp11.widen match
784+
case OrNull(tp11a) if recur(tp11a, tp2) => return true
785+
case _ =>
786+
773787
// Rewrite (T111 | T112) & T12 <: T2 to (T111 & T12) <: T2 and (T112 | T12) <: T2
774788
// and analogously for T11 & (T121 | T122) & T12 <: T2
775789
// `&' types to the left of <: are problematic, because
@@ -1042,7 +1056,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
10421056
*/
10431057
def isNewSubType(tp1: Type): Boolean =
10441058
if (isCovered(tp1) && isCovered(tp2))
1045-
//println(s"useless subtype: $tp1 <:< $tp2")
1059+
//println(i"useless subtype: $tp1 <:< $tp2")
10461060
false
10471061
else isSubType(tp1, tp2, approx.addLow)
10481062

@@ -1533,7 +1547,11 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
15331547
* combiners are AppliedTypes, RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes.
15341548
*/
15351549
private def isCovered(tp: Type): Boolean = tp.dealiasKeepRefiningAnnots.stripTypeVar match {
1536-
case tp: TypeRef => tp.symbol.isClass && tp.symbol != NothingClass && tp.symbol != NullClass
1550+
case tp: TypeRef =>
1551+
tp.symbol.isClass
1552+
&& tp.symbol != NothingClass
1553+
&& tp.symbol != NullClass
1554+
&& tp.symbol != NotNullClass
15371555
case tp: AppliedType => isCovered(tp.tycon)
15381556
case tp: RefinedOrRecType => isCovered(tp.parent)
15391557
case tp: AndType => isCovered(tp.tp1) && isCovered(tp.tp2)
@@ -1701,28 +1719,27 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
17011719
tp11 & tp2 | tp12 & tp2
17021720
case _ =>
17031721
val tp1a = dropIfSuper(tp1, tp2)
1704-
if (tp1a ne tp1) glb(tp1a, tp2)
1705-
else {
1706-
val tp2a = dropIfSuper(tp2, tp1)
1707-
if (tp2a ne tp2) glb(tp1, tp2a)
1708-
else tp1 match {
1709-
case tp1: ConstantType =>
1710-
tp2 match {
1711-
case tp2: ConstantType =>
1712-
// Make use of the fact that the intersection of two constant types
1713-
// types which are not subtypes of each other is known to be empty.
1714-
// Note: The same does not apply to singleton types in general.
1715-
// E.g. we could have a pattern match against `x.type & y.type`
1716-
// which might succeed if `x` and `y` happen to be the same ref
1717-
// at run time. It would not work to replace that with `Nothing`.
1718-
// However, maybe we can still apply the replacement to
1719-
// types which are not explicitly written.
1720-
NothingType
1721-
case _ => andType(tp1, tp2)
1722-
}
1723-
case _ => andType(tp1, tp2)
1724-
}
1725-
}
1722+
if (tp1a ne tp1) return glb(tp1a, tp2)
1723+
val tp2a = dropIfSuper(tp2, tp1)
1724+
if (tp2a ne tp2) return glb(tp1, tp2a)
1725+
tp1 match
1726+
case tp1: ConstantType =>
1727+
tp2 match
1728+
case tp2: ConstantType =>
1729+
// Make use of the fact that the intersection of two constant types
1730+
// types which are not subtypes of each other is known to be empty.
1731+
// Note: The same does not apply to singleton types in general.
1732+
// E.g. we could have a pattern match against `x.type & y.type`
1733+
// which might succeed if `x` and `y` happen to be the same ref
1734+
// at run time. It would not work to replace that with `Nothing`.
1735+
// However, maybe we can still apply the replacement to
1736+
// types which are not explicitly written.
1737+
return NothingType
1738+
case _ =>
1739+
case _ =>
1740+
if tp1.isRef(NotNullClass) && tp2.isNull then return NothingType
1741+
if tp2.isRef(NotNullClass) && tp1.isNull then return NothingType
1742+
andType(tp1, tp2)
17261743
}
17271744
}
17281745
}
@@ -1838,7 +1855,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
18381855
else if (!tp2.exists) tp1
18391856
else tp.derivedAndType(tp1, tp2)
18401857

1841-
/** If some (&-operand of) this type is a supertype of `sub` replace it with `NoType`.
1858+
/** If some (&-operand of) `tp` is a supertype of `sub` replace it with `NoType`.
18421859
*/
18431860
private def dropIfSuper(tp: Type, sub: Type): Type =
18441861
if (isSubTypeWhenFrozen(sub, tp)) NoType

compiler/src/dotty/tools/dotc/interactive/Completion.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ object Completion {
207207
def addMemberCompletions(qual: Tree)(implicit ctx: Context): Unit =
208208
if (!qual.tpe.widenDealias.isBottomType) {
209209
addAccessibleMembers(qual.tpe)
210-
if (!mode.is(Mode.Import) && !qual.tpe.isRef(defn.NullClass))
210+
if (!mode.is(Mode.Import) && !qual.tpe.isNull)
211211
// Implicit conversions do not kick in when importing
212212
// and for `NullClass` they produce unapplicable completions (for unclear reasons)
213213
implicitConversionTargets(qual)(ctx.fresh.setExploreTyperState())

0 commit comments

Comments
 (0)